/**
 @file sys_usw_nexthop_srv6.c

 @date 2011-05-23

 @version v2.0

 The file contains all nexthop ip tunnel related callback function
*/

/****************************************************************************
 *
* Header Files
*
****************************************************************************/
#include "ctc_const.h"
#include "ctc_macro.h"
#include "ctc_error.h"
#include "ctc_linklist.h"
#include "sys_usw_common.h"
#include "sys_usw_internal_port.h"
#include "sys_usw_nexthop_api.h"
#include "sys_usw_nexthop_hw.h"
#include "sys_usw_nexthop.h"
#include "sys_usw_vlan.h"
#include "sys_usw_stats_api.h"
#include "sys_usw_l3if.h"
#include "sys_usw_register.h"
#include "sys_usw_qos_api.h"
#include "sys_usw_aps.h"

#include "sys_usw_wb_nh.h"

#include "usw/include/drv_io.h"

/****************************************************************************
 *
* Defines and Macros
*
*****************************************************************************/
#define SYS_USW_MAX_SRH_ID 0x3FFFFFFF
extern int32 _sys_usw_nh_ip_tunnel_alloc_ipsa_idx(uint8 lchip, uint8 ip_ver, void* p_add, uint8* p_index, uint8 old_index);
extern int32 _sys_usw_nh_ip_tunnel_free_ipsa_idx(uint8 lchip, uint8 ip_ver, uint8 index);
#define SYS_NH_SRV6_MAX_SID_NUM 3
sys_nh_db_srh_t*
_sys_usw_nh_lkup_srh_id(uint8 lchip, uint32 srh_id)
{
    sys_nh_db_srh_t srh_db;
    sal_memset(&srh_db, 0, sizeof(sys_nh_db_srh_t));
    srh_db.srh_id = srh_id;
    return ctc_hash_lookup(g_usw_nh_master[lchip]->srh_id_hash, &srh_db);
}

STATIC uint32
_sys_usw_nh_srv6_srh_param_chk(uint8 lchip, ctc_nh_srh_edit_param_t* p_nh_param)
{
    uint32 sid_edit_mode = 0;
    CTC_ERROR_RETURN(sys_usw_global_ctl_get(lchip, CTC_GLOBAL_SID_EDIT_MODE, &sid_edit_mode));

    if ((p_nh_param->num > SYS_NEXTHOP_SRV6_SR_NUM))
    {
        return CTC_E_INVALID_PARAM;
    }

    if ((0 == sid_edit_mode) && (0 == p_nh_param->num) && p_nh_param->reduce)
    {
        return CTC_E_INVALID_PARAM;
    }
    CTC_MAX_VALUE_CHECK(p_nh_param->ldp, MCHIP_CAP(SYS_CAP_NH_MAX_LOGIC_DEST_PORT));

    return CTC_E_NONE;
}

STATIC uint32
_sys_usw_nh_srv6_build_srh(uint8 lchip, ctc_nh_srh_edit_param_t* p_nh_param, sys_nh_db_srh_t* srh_db)
{
    uint8 i = 0;
    sys_dsl3edit_srh_t sys_srh;
    uint8 is_reduce = 0;
    uint32 sid_edit_mode = 0;
    sys_nh_db_arp_t* p_arp = NULL;
    sys_ldp_t sys_ldp;
    sys_l3if_prop_t l3if_prop;

    sal_memset(&sys_ldp, 0, sizeof(sys_ldp_t));
    sal_memset(&sys_srh, 0, sizeof(sys_srh));
    sal_memset(&l3if_prop, 0, sizeof(l3if_prop));

    if (p_nh_param->arp_id)
    {
        p_arp = (sys_usw_nh_lkup_arp_id(lchip, p_nh_param->arp_id));
        if (NULL == p_arp)
        {
            return CTC_E_NOT_EXIST;
        }
        sys_srh.l2edit_ptr = p_arp->offset;
        sys_srh.out_l2edit_valid = sys_srh.l2edit_ptr ? 1 : 0;
        l3if_prop.l3if_id = p_arp->l3if_id;
        CTC_ERROR_RETURN(sys_usw_l3if_get_l3if_info(lchip, 1,&l3if_prop));
    }

    CTC_ERROR_RETURN(sys_usw_global_ctl_get(lchip, CTC_GLOBAL_SID_EDIT_MODE, &sid_edit_mode));
    if ((p_nh_param->reduce) || (1 == sid_edit_mode))
    {
        is_reduce = 1;
    }
    sys_srh.segment_left = p_nh_param->num - 1 + (sid_edit_mode? 1 : 0);
    sys_srh.last_entry = sys_srh.segment_left - is_reduce;
    sys_srh.header_len = (sys_srh.last_entry + 1)*2;

    /*
    1. replacePRAsFirstSegment always 1; segment0 ~ segment2 total in spec
    2. EpePktProcCtl.sr6ReducedMode = 1, new ipda get from segment2 in DsL3EditAddIp6ExtHeader
    3. EpePktProcCtl.sr6ReducedMode = 0, new ipda get from reducedFirstSegment in DsL3EditAddIp6Sr */
    sys_srh.sid_list[2][0] = p_nh_param->sid_list[p_nh_param->num - 1][3];
    sys_srh.sid_list[2][1] = p_nh_param->sid_list[p_nh_param->num - 1][2];
    sys_srh.sid_list[2][2] = p_nh_param->sid_list[p_nh_param->num - 1][1];
    sys_srh.sid_list[2][3] = p_nh_param->sid_list[p_nh_param->num - 1][0];
    for (i = 0; i < p_nh_param->num; i++)
    {
        sys_srh.sid_list[i][0] = p_nh_param->sid_list[i][3];
        sys_srh.sid_list[i][1] = p_nh_param->sid_list[i][2];
        sys_srh.sid_list[i][2] = p_nh_param->sid_list[i][1];
        sys_srh.sid_list[i][3] = p_nh_param->sid_list[i][0];
    }

    if(CTC_FLAG_ISSET(p_nh_param->flag, CTC_NH_SRH_FLAG_DENY_REPLACE_IPDA))
    {
        CTC_SET_FLAG(srh_db->flag, SYS_NH_SRH_FLAG_DENY_REPLACE_IPDA);
        sys_srh.replace_ipda = 0;
    }
    else
    {
        CTC_UNSET_FLAG(srh_db->flag, SYS_NH_SRH_FLAG_DENY_REPLACE_IPDA);
        sys_srh.replace_ipda = 1;
    }
    CTC_ERROR_RETURN(sys_usw_nh_write_asic_table(lchip, SYS_NH_ENTRY_TYPE_L3EDIT_SRH +  SYS_NH_TYPE_STEP_TO_INNER, srh_db->l3edit_ptr, &sys_srh));

    srh_db->is_reduce = is_reduce;
    srh_db->segment_left = sys_srh.segment_left;
    srh_db->num = p_nh_param->num;
    if (p_nh_param->ldp)
    {
        /*used for Write DsLogicDestPort*/
        sys_ldp.l3edit_ptr   = srh_db->l3edit_ptr;
        if (DRV_FROM_AT(lchip))
        {
            sys_ldp.edit_mode = 1;
        }
        CTC_ERROR_RETURN(sys_usw_nh_write_asic_table(lchip, SYS_NH_ENTRY_TYPE_LOGIC_DEST_PORT, p_nh_param->ldp, &sys_ldp));
    }

    return CTC_E_NONE;
}

STATIC int32
_sys_usw_nh_srv6_map_tunnelv6(uint8 lchip, sys_dsl3edit_srv6_t* dsl3edit_srv6,
                                           sys_dsl3edit_tunnelv6_t* dsl3edit_tunnelv6)
{

    dsl3edit_tunnelv6->ds_type               = SYS_NH_DS_TYPE_L3EDIT;
    dsl3edit_tunnelv6->l3_rewrite_type       = DRV_ENUM(DRV_L3EDITTYPE_ADDIP6);
    dsl3edit_tunnelv6->out_l2edit_valid      = dsl3edit_srv6->out_l2edit_valid;
    dsl3edit_tunnelv6->l2edit_ptr            = dsl3edit_srv6->l2edit_ptr;
    dsl3edit_tunnelv6->ecn_mode              = dsl3edit_srv6->ecn_mode;
    dsl3edit_tunnelv6->mtu_check_en          = dsl3edit_srv6->mtu_check_en;
    dsl3edit_tunnelv6->mtu_size              = dsl3edit_srv6->mtu_size;
    dsl3edit_tunnelv6->map_ttl               = dsl3edit_srv6->map_ttl;
    dsl3edit_tunnelv6->new_flow_label_mode   = dsl3edit_srv6->new_flow_label_mode;
    dsl3edit_tunnelv6->ttl                   = dsl3edit_srv6->ttl;
    dsl3edit_tunnelv6->flow_label            = dsl3edit_srv6->flow_label;
    dsl3edit_tunnelv6->new_flow_label_valid  = dsl3edit_srv6->new_flow_label_valid;
    dsl3edit_tunnelv6->ipda[0]               = dsl3edit_srv6->ipda[0];
    dsl3edit_tunnelv6->ipda[1]               = dsl3edit_srv6->ipda[1];
    dsl3edit_tunnelv6->ipda[2]               = dsl3edit_srv6->ipda[2];
    dsl3edit_tunnelv6->ipda[3]               = dsl3edit_srv6->ipda[3];
    dsl3edit_tunnelv6->stats_ptr             = dsl3edit_srv6->stats_ptr;
    dsl3edit_tunnelv6->derive_dscp           = dsl3edit_srv6->derive_dscp;
    dsl3edit_tunnelv6->tos                   = dsl3edit_srv6->tos;
    dsl3edit_tunnelv6->dscp_domain           = dsl3edit_srv6->dscp_domain;
    dsl3edit_tunnelv6->auto_protocol         = 1;
    dsl3edit_tunnelv6->share_type = SYS_NH_L3EDIT_TUNNELV6_SHARE_TYPE_NORMAL;
    dsl3edit_tunnelv6->ip_protocol_type = dsl3edit_srv6->header_type;
    dsl3edit_tunnelv6->ipsa_index = dsl3edit_srv6->ipsa_index;
    dsl3edit_tunnelv6->xedit_ptr = dsl3edit_srv6->xedit_ptr;

    return CTC_E_NONE;
}


STATIC int32
_sys_usw_nh_srv6_build_dsl3edit(uint8 lchip, sys_nh_param_srv6_t* p_nh_srv6_param,
                                           sys_nh_info_srv6_t* p_edit_db,
                                           sys_nh_param_dsnh_t* dsnh)
{
    sys_dsl3edit_srv6_t dsl3edit_srv6;
    sys_dsl3edit_tunnelv6_t dsl3edit_tunnelv6;
    void* p_dsl3edit;
    uint8 edit_type = 0;
    ipv6_addr_t vpn_sid_tmp;
    uint8 sa_index = MCHIP_CAP(SYS_CAP_NH_IP_TUNNEL_INVALID_IPSA_NUM);
    ctc_nh_srv6_param_t *p_nh_param = NULL;

    sal_memset(&dsl3edit_srv6, 0, sizeof(dsl3edit_srv6));
    sal_memset(&dsl3edit_tunnelv6, 0, sizeof(dsl3edit_tunnelv6));
    sal_memset(&vpn_sid_tmp, 0, sizeof(ipv6_addr_t));

    p_nh_param = p_nh_srv6_param->p_srv6_nh_param;

    if ((CTC_NH_SRV6_TYPE_E_ENCAPS == p_nh_param->srv6_type)
        || (CTC_NH_SRV6_TYPE_H_ENCAPS == p_nh_param->srv6_type)
        || (CTC_NH_SRV6_TYPE_H_ENCAPS_L2 == p_nh_param->srv6_type))
    {
        dsl3edit_srv6.l3_rewrite_type = DRV_ENUM(DRV_L3EDITTYPE_ADDIP68X);
        edit_type = SYS_NH_ENTRY_TYPE_L3EDIT_ADD_SRV6;
        CTC_SET_FLAG(p_edit_db->flag, SYS_NH_SRV6_FLAG_ENCAP);
    }
    else
    {
        dsl3edit_srv6.l3_rewrite_type = DRV_ENUM(DRV_L3EDITTYPE_RWIP68X);
        edit_type = SYS_NH_ENTRY_TYPE_L3EDIT_RW_SRV6;
    }
    dsl3edit_srv6.header_type = 43;/* Next Header in IPv6 Tunnel*/

    if (CTC_FLAG_ISSET(p_nh_param->flag, CTC_NH_SRV6_FLAG_IP_BFD))
    {
        dsl3edit_srv6.next_header = 17; /*UDP*/
        dsl3edit_srv6.next_header_en = 1;
    }

    if (CTC_FLAG_ISSET(p_nh_param->flag, CTC_NH_SRV6_FLAG_UPDATE_UDP_CHKSUM))
    {
        dsl3edit_srv6.upd_chksum = 1;
    }

    if (CTC_FLAG_ISSET(p_edit_db->flag, SYS_NH_SRV6_FLAG_ENCAP))
    {
        dsl3edit_srv6.ttl = p_nh_param->ttl;
        dsl3edit_srv6.map_ttl = CTC_FLAG_ISSET(p_nh_param->flag,
                                               CTC_NH_SRV6_FLAG_MAP_TTL);
    }

    if (p_nh_param->stats_id &&
        ((p_nh_param->flow_label_mode == CTC_NH_FLOW_LABEL_NONE)
           || (0 ==  CTC_FLAG_ISSET(p_edit_db->flag, SYS_NH_SRV6_FLAG_ENCAP))))
    {
        CTC_ERROR_RETURN(sys_usw_flow_stats_get_statsptr(lchip,
                                                           p_nh_param->stats_id,
                                                           &(dsl3edit_srv6.stats_ptr)));
    }
    if (p_nh_param->dscp_select == CTC_NH_DSCP_SELECT_ASSIGN)
    {
        CTC_MAX_VALUE_CHECK(p_nh_param->dscp_or_tos, 63);
        dsl3edit_srv6.derive_dscp = 1;
        dsl3edit_srv6.tos = (p_nh_param->dscp_or_tos<<2);
    }
    else if (p_nh_param->dscp_select == CTC_NH_DSCP_SELECT_MAP)
    {
        dsl3edit_srv6.derive_dscp = 2;
        dsl3edit_srv6.tos = 1 << 0;
        dsl3edit_srv6.dscp_domain = p_nh_param->dscp_domain;
    }
    else if (p_nh_param->dscp_select == CTC_NH_DSCP_SELECT_PACKET)
    {
        dsl3edit_srv6.derive_dscp = 3;
        dsl3edit_srv6.tos = 0 << 0;
    }
    else if (p_nh_param->dscp_select == CTC_NH_DSCP_SELECT_NONE)
    {
        dsl3edit_srv6.derive_dscp = 0;
    }
    else
    {
        return CTC_E_INVALID_PARAM;
    }

    if (p_nh_param->ecn_select ==  CTC_NH_ECN_SELECT_NONE)
    {
        dsl3edit_srv6.ecn_mode = CTC_FLAG_ISSET(p_edit_db->flag, SYS_NH_SRV6_FLAG_ENCAP)? 3 : 1;
        dsl3edit_srv6.tos = dsl3edit_srv6.tos & 0xFC;
    }
    else if (p_nh_param->ecn_select ==  CTC_NH_ECN_SELECT_ASSIGN)
    {
        return CTC_E_NOT_SUPPORT;
    }
    else if (p_nh_param->ecn_select ==  CTC_NH_ECN_SELECT_MAP)
    {
        dsl3edit_srv6.ecn_mode = CTC_FLAG_ISSET(p_edit_db->flag, SYS_NH_SRV6_FLAG_ENCAP)? 1 : 2;
    }
    else if (p_nh_param->ecn_select ==  CTC_NH_ECN_SELECT_PACKET)
    {
        dsl3edit_srv6.ecn_mode = 0;
    }

    if (p_nh_param->flow_label_mode == CTC_NH_FLOW_LABEL_NONE)
    {
        dsl3edit_srv6.new_flow_label_valid = 0x0;
    }
    else if (p_nh_param->flow_label_mode == CTC_NH_FLOW_LABEL_WITH_HASH ||
             p_nh_param->flow_label_mode == CTC_NH_FLOW_LABEL_ASSIGN)
    {
        if (p_nh_param->flow_label > 0xFFFFF)
        {
            return CTC_E_INVALID_PARAM;
        }
        dsl3edit_srv6.new_flow_label_valid = 0x1;
        dsl3edit_srv6.new_flow_label_mode = (p_nh_param->flow_label_mode == CTC_NH_FLOW_LABEL_WITH_HASH);
        dsl3edit_srv6.flow_label = p_nh_param->flow_label;
    }
    else
    {
        return CTC_E_INVALID_PARAM;
    }

    if (CTC_FLAG_ISSET(p_nh_param->flag, CTC_NH_SRV6_FLAG_MTU_CHECK))
    {
        if (p_nh_param->mtu_size > 0x3FFF)
        {
            return CTC_E_INVALID_PARAM;
        }

        dsl3edit_srv6.mtu_check_en = 1;
        dsl3edit_srv6.mtu_size = p_nh_param->mtu_size & 0x3FFF;
    }

    dsl3edit_srv6.ipda[0] = p_nh_param->ip_da[3];
    dsl3edit_srv6.ipda[1] = p_nh_param->ip_da[2];
    dsl3edit_srv6.ipda[2] = p_nh_param->ip_da[1];
    dsl3edit_srv6.ipda[3] = p_nh_param->ip_da[0];
    dsl3edit_srv6.vpn_sid[0] = p_nh_param->vpn_sid[3];
    dsl3edit_srv6.vpn_sid[1] = p_nh_param->vpn_sid[2];
    dsl3edit_srv6.vpn_sid[2] = p_nh_param->vpn_sid[1];
    dsl3edit_srv6.vpn_sid[3] = p_nh_param->vpn_sid[0];

    if(CTC_NH_SRV6_TYPE_E_INSERT == p_nh_param->srv6_type)
    {
        dsl3edit_srv6.replace_last = 0;
        p_edit_db->replace_last = 0;
    }
    else if ((CTC_NH_SRV6_TYPE_H_INSERT == p_nh_param->srv6_type) ||
            (sal_memcmp(dsl3edit_srv6.vpn_sid, vpn_sid_tmp, sizeof(ipv6_addr_t))
            && ((p_nh_srv6_param->p_tnl && !CTC_FLAG_ISSET(p_nh_srv6_param->p_tnl->flag, SYS_NH_SRH_FLAG_DENY_REPLACE_IPDA))
            || ((0 != p_edit_db->ecmp_if_id) && CTC_FLAG_ISSET(p_edit_db->flag, SYS_NH_SRV6_FLAG_SRH_REPLACE_IPDA)))))
    {
        dsl3edit_srv6.replace_last = 1;
        p_edit_db->replace_last = 1;
    }

    if (p_edit_db->outer_l2_edit_offset)
    {
        dsl3edit_srv6.out_l2edit_valid = 1;
        dsl3edit_srv6.l2edit_ptr = p_edit_db->outer_l2_edit_offset;
    }

    if (DRV_FROM_AT(lchip) && p_nh_param->fp_id && MCHIP_NH(lchip)->get_fp_info)
    {
        sys_nh_info_dsnh_t fp_info;
        sal_memset(&fp_info, 0, sizeof(fp_info));
        CTC_ERROR_RETURN(MCHIP_NH(lchip)->get_fp_info(lchip, p_nh_param->fp_id, &fp_info));
        if (0 == fp_info.fp2)
        {
            return CTC_E_INVALID_CONFIG;
        }
        dsl3edit_srv6.xedit_ptr = fp_info.l3_edit_ptr;
        p_edit_db->fp_id = p_nh_param->fp_id;
    }

    p_dsl3edit = &dsl3edit_srv6;

    /* Config IPSA*/
    if ((CTC_NH_SRV6_TYPE_H_ENCAPS == p_nh_param->srv6_type ||
        CTC_NH_SRV6_TYPE_H_ENCAPS_L2 == p_nh_param->srv6_type))
    {
        CTC_ERROR_RETURN(_sys_usw_nh_ip_tunnel_alloc_ipsa_idx(lchip, CTC_IP_VER_6, p_nh_param->ip_sa, &sa_index, p_edit_db->ipsa_index));
        p_edit_db->ipsa_index = sa_index&0xF;
        dsl3edit_srv6.ipsa_index = sa_index&0xF;
        CTC_SET_FLAG(p_edit_db->flag,SYS_NH_SRV6_FLAG_HAVE_IPSA);
    }

    if (((p_nh_srv6_param->p_tnl && !p_nh_srv6_param->p_tnl->num) && !CTC_FLAG_ISSET(p_nh_srv6_param->p_tnl->flag, SYS_NH_SRH_FLAG_APS))
       || ((0 != p_edit_db->ecmp_if_id) && !CTC_FLAG_ISSET(p_edit_db->flag, SYS_NH_SRV6_FLAG_SRH_IS_LDP)))
    {
        if(CTC_NH_SRV6_TYPE_H_ENCAPS_L2 == p_nh_param->srv6_type)
        {
            dsl3edit_srv6.header_type = 143;/*ETH*/
        }
        _sys_usw_nh_srv6_map_tunnelv6(lchip, &dsl3edit_srv6, &dsl3edit_tunnelv6);
        p_dsl3edit = &dsl3edit_tunnelv6;
        CTC_ERROR_RETURN(sys_usw_nh_add_l3edit_tunnel(lchip, p_dsl3edit, SYS_NH_ENTRY_TYPE_L3EDIT_TUNNEL_V6, &dsnh->l3edit_ptr));
    }
    else
    {
        CTC_ERROR_RETURN(sys_usw_nh_offset_alloc(lchip, edit_type, 1, &dsnh->l3edit_ptr));
        if(CTC_E_NONE != sys_usw_nh_write_asic_table(lchip, edit_type, dsnh->l3edit_ptr, &dsl3edit_srv6))
        {
             sys_usw_nh_offset_free(lchip, edit_type, 1, dsnh->l3edit_ptr);
        }
    }

    p_edit_db->dsl3edit_offset = dsnh->l3edit_ptr;
    return CTC_E_NONE;
}

STATIC int32
_sys_usw_nh_srv6_build_dsl2edit(uint8 lchip, sys_nh_param_srv6_t* p_nh_param,
                                           sys_nh_info_srv6_t* p_edit_db,
                                           sys_nh_param_dsnh_t* dsnh)
{
    sys_dsl2edit_eth_t   dsl2edit;
    mac_addr_t mac = {0};
    sal_memset(&dsl2edit, 0 , sizeof(sys_dsl2edit_eth_t));

    if (p_nh_param->p_tnl && p_nh_param->p_tnl->arp_id)
    {
        sys_nh_db_arp_t* p_arp = NULL;
        p_arp = (sys_usw_nh_lkup_arp_id(lchip, p_nh_param->p_tnl->arp_id));
        if (NULL == p_arp)
        {
            return CTC_E_NOT_EXIST;
        }
        dsnh->l2edit_ptr = p_arp->offset;
        p_edit_db->outer_l2_edit_offset = dsnh->l2edit_ptr;
    }
    else
    {
        sal_memcpy(dsl2edit.mac_da, p_nh_param->mac, sizeof(mac_addr_t));
        dsl2edit.output_vid =  p_nh_param->oif.vid;
        if (!sal_memcmp(p_nh_param->mac, mac, sizeof(mac_addr_t)))
        {
            dsl2edit.derive_mcast_mac_for_ip = 1;
        }
        CTC_ERROR_RETURN(sys_usw_nh_add_l2edit(lchip, &dsl2edit, SYS_NH_ENTRY_TYPE_L2EDIT_OUTER_4W, &dsnh->l2edit_ptr));
        p_edit_db->outer_l2_edit_offset = dsnh->l2edit_ptr;
    }

    return CTC_E_NONE;
}

int32
_sys_usw_nh_srv6_update_tnl_mem(uint8 lchip, sys_nh_info_com_t* p_nhinfo, sys_nh_db_srh_t *p_tnl, uint8 is_add)
{
    sys_nh_ref_list_node_t* p_curr = NULL;
    sys_nh_ref_list_node_t** p_head = NULL;
    sys_nh_ref_list_node_t* p_nh_ref_list_node = NULL;
    sys_nh_ref_list_node_t* p_prev = NULL;
    uint8 find_flag = 0;

    if(!p_tnl)
    {
         return CTC_E_NONE;
    }

    if (p_nhinfo->hdr.nh_entry_type != SYS_NH_TYPE_ECMP)
    {
        p_curr = p_tnl->pd->nh_list;
        p_head = (sys_nh_ref_list_node_t**)&p_tnl->pd->nh_list;
    }
    else
    {
        p_curr = p_tnl->pd->ecmp_list;
        p_head = (sys_nh_ref_list_node_t**)&p_tnl->pd->ecmp_list;
    }
    if (is_add)
    {
        while (p_curr)
        {
            if (p_curr->p_ref_nhinfo == p_nhinfo)
            {
                find_flag = 1;
                break;
            }

            p_curr = p_curr->p_next;
        }

        if (find_flag == 0)
        {
            p_nh_ref_list_node = (sys_nh_ref_list_node_t*)mem_malloc(MEM_NEXTHOP_MODULE, sizeof(sys_nh_ref_list_node_t));
            if (p_nh_ref_list_node == NULL)
            {
                SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " No memory \n");
                return CTC_E_NO_MEMORY;
            }
            p_nh_ref_list_node->p_ref_nhinfo = (sys_nh_info_com_t* )p_nhinfo;
            p_nh_ref_list_node->p_next = *p_head;
            *p_head = p_nh_ref_list_node;
        }
    }
    else
    {
        while (p_curr)   /* If p_nhinfo equal to NULL, only minus reference count*/
        {
            if (p_curr->p_ref_nhinfo == p_nhinfo)
            {
                if (NULL == p_prev)
                /*Remove first node*/
                {
                   *p_head = p_curr->p_next;
                }
                else
                {
                    p_prev->p_next = p_curr->p_next;
                }

                mem_free(p_curr);
                break;
            }
            p_prev = p_curr;
            p_curr = p_curr->p_next;
        }
    }

    return CTC_E_NONE;
}

STATIC int32
_sys_usw_nh_free_srv6_resource(uint8 lchip, sys_nh_info_srv6_t* p_nh_info, sys_nh_info_srv6_t* p_new_info)
{

    uint8 l3edit_type = 0;
    sys_nh_db_srh_t    *p_srh_tnl = NULL;

    p_srh_tnl = _sys_usw_nh_lkup_srh_id(lchip, p_nh_info->srh_id);
    if (CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_NO_HW))
    {
        goto update_tnl;
    }

    if (p_nh_info->aps_xcon_met && (0 != p_nh_info->met_offset))
    {
        sys_usw_nh_offset_free(lchip, SYS_NH_ENTRY_TYPE_MET, 1, p_nh_info->met_offset);
        p_nh_info->aps_xcon_met = 0;
        p_nh_info->met_offset = 0;
    }

    if (CTC_FLAG_ISSET(p_nh_info->flag, SYS_NH_SRV6_FLAG_HAVE_IPSA))
    {
        _sys_usw_nh_ip_tunnel_free_ipsa_idx(lchip, CTC_IP_VER_6, p_nh_info->ipsa_index);
         CTC_UNSET_FLAG(p_nh_info->flag, SYS_NH_SRV6_FLAG_HAVE_IPSA);
    }
    if (CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L3EDIT))
    {
        if(((p_srh_tnl && !p_srh_tnl->num) && !CTC_FLAG_ISSET(p_srh_tnl->flag, SYS_NH_SRH_FLAG_APS))
            || ((0 != p_nh_info->ecmp_if_id) && !CTC_FLAG_ISSET(p_nh_info->flag, SYS_NH_SRV6_FLAG_SRH_IS_LDP)))
        {
            l3edit_type = SYS_NH_ENTRY_TYPE_L3EDIT_TUNNEL_V6;
            sys_usw_nh_remove_l3edit_tunnel(lchip, l3edit_type, p_nh_info->dsl3edit_offset);
        }
        else
        {
            l3edit_type = CTC_FLAG_ISSET(p_nh_info->flag, SYS_NH_SRV6_FLAG_ENCAP) ? SYS_NH_ENTRY_TYPE_L3EDIT_ADD_SRV6 : SYS_NH_ENTRY_TYPE_L3EDIT_RW_SRV6;
            sys_usw_nh_offset_free(lchip, l3edit_type, 1, p_nh_info->dsl3edit_offset);
        }
    }

    if (CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L2EDIT)
    && p_srh_tnl && (!p_srh_tnl->arp_id))
    {
        sys_usw_nh_remove_l2edit(lchip, SYS_NH_ENTRY_TYPE_L2EDIT_OUTER_4W, p_nh_info->outer_l2_edit_offset);
    }

    if (CTC_FLAG_ISSET(p_nh_info->flag, SYS_NH_SRV6_FLAG_LOOP_NH) )
    {
        sys_usw_nh_remove_loopback_l2edit(lchip, p_nh_info->outer_l2_edit_offset, TRUE);
        p_nh_info->outer_l2_edit_offset = 0;
        CTC_UNSET_FLAG(p_nh_info->flag, SYS_NH_SRV6_FLAG_LOOP_NH);
    }

    if (p_nh_info->service_id)
    {
        /*Call QoS for unbinding service with logic Port*/
        sys_usw_qos_unbind_service_logic_dstport(lchip, p_nh_info->service_id, p_nh_info->dest_logic_port,p_nh_info->gport);
        p_nh_info->service_id = 0;
    }

    p_nh_info->flag = 0;
    CTC_UNSET_FLAG(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L3EDIT);
    CTC_UNSET_FLAG(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L2EDIT);

    /*p_new_info only used for srv6 nexthop update to free old nexthop info,
        for delete and other resource rollback, p_new_info should be NULL*/
update_tnl:        
    if(!p_new_info || p_nh_info->srh_id != p_new_info->srh_id)
    {
        _sys_usw_nh_srv6_update_tnl_mem(lchip,p_new_info ? (sys_nh_info_com_t*)p_new_info:(sys_nh_info_com_t*)p_nh_info, p_srh_tnl, 0);
        p_nh_info->srh_id = 0;
    }

    return CTC_E_NONE;
}

STATIC int32
_sys_usw_nh_srv6_build_dsnh(uint8 lchip, sys_nh_param_srv6_t* p_nh_param,
                                       sys_nh_info_srv6_t* p_edit_db,
                                       sys_nh_param_dsfwd_t * p_fwd_info)
{
    uint8 gchip = 0;
    sys_nh_param_dsnh_t dsnh_param;
    sys_l3if_prop_t l3if_prop;
    uint32 gport = 0;
    uint16 lport = 0;
    uint32 stats_ptr = 0;
    int32 ret = CTC_E_NONE;
    ctc_nh_srv6_param_t* p_nh_srv6_param;
    uint8 srh_aps_en = 0;
    uint8 is_update = (p_nh_param->hdr.change_type != SYS_NH_CHANGE_TYPE_NULL);

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    sal_memset(&dsnh_param, 0, sizeof(sys_nh_param_dsnh_t));
    sal_memset(&l3if_prop, 0, sizeof(sys_l3if_prop_t));

    if (!is_update)
    {
        p_edit_db->ipsa_index = 0xFF;
    }

    p_nh_srv6_param = p_nh_param->p_srv6_nh_param;
    p_edit_db->srv6_type = p_nh_srv6_param->srv6_type;

    sys_usw_get_gchip_id(lchip, &gchip);
    srh_aps_en = (p_nh_param->p_tnl && CTC_FLAG_ISSET(p_nh_param->p_tnl->flag, SYS_NH_SRH_FLAG_APS))? 1 : 0;
    if (srh_aps_en)
    {
        p_edit_db->gport = p_nh_param->p_tnl->arp_id;
        CTC_SET_FLAG(p_edit_db->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_IS_APS_EN);
        CTC_SET_FLAG(p_edit_db->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_IS_APS_SHARE_DSNH);
    }
    else if (p_edit_db->ecmp_if_id)
    {
        //destmap = SYS_ENCODE_ECMP_DESTMAP(p_edit_db->ecmp_if_id)
    }
    else if (!CTC_FLAG_ISSET(p_nh_srv6_param->flag, CTC_NH_SRV6_FLAG_REROUTE) && (p_nh_srv6_param->loop_nhid == 0))
    {
        gchip = SYS_MAP_CTC_GPORT_TO_GCHIP(p_nh_param->oif.gport);
        gport = p_nh_param->oif.gport;
        if (!(CTC_IS_CPU_PORT(p_nh_param->oif.gport) || p_nh_param->oif.is_l2_port || p_nh_param->hdr.is_drop) && !p_nh_param->hdr.l3if_id)
        {
            CTC_ERROR_RETURN(sys_usw_l3if_get_l3if_info_with_port_and_vlan(lchip, gport, p_nh_param->oif.vid, p_nh_param->oif.cvid, &l3if_prop))
            p_edit_db->l3ifid  = l3if_prop.l3if_id;
        }
        else
        {
            l3if_prop.vlan_ptr = 0xFFFF;
            p_edit_db->l3ifid  = p_nh_param->hdr.l3if_id;
            if (p_nh_param->hdr.l3if_id)
            {
                l3if_prop.l3if_id = p_nh_param->hdr.l3if_id;
                CTC_ERROR_RETURN(sys_usw_l3if_get_l3if_info(lchip, 1, &l3if_prop));
            }
        }
        p_edit_db->gport = gport;
    }
    else if (p_nh_srv6_param->loop_nhid)
    {
        sys_nh_info_dsnh_t nhinfo;
        sal_memset(&nhinfo, 0, sizeof(nhinfo));
        CTC_ERROR_RETURN(_sys_usw_nh_get_nhinfo(lchip, p_nh_srv6_param->loop_nhid, &nhinfo));
        sys_usw_internal_port_get_rsv_port(lchip, SYS_INTERNAL_PORT_TYPE_ELOOP, nhinfo.gport, &lport);
        p_edit_db->gport = SYS_MAP_DRV_LPORT_TO_CTC_GPORT(gchip, lport);
        l3if_prop.vlan_ptr = MCHIP_CAP(SYS_CAP_L3IF_RSV_L3IF_ID) + MCHIP_CAP(SYS_CAP_L3IF_VLAN_PTR_BASE);
    }
    else if (CTC_FLAG_ISSET(p_nh_srv6_param->flag, CTC_NH_SRV6_FLAG_REROUTE))
    {   /*if need loopback, get egress loopback port*/
        CTC_ERROR_RETURN(sys_usw_internal_port_get_rsv_port(lchip, SYS_INTERNAL_PORT_TYPE_IP_TUNNEL, 0, &lport));
        p_nh_param->oif.gport = lport; /*only use lport (IP tunnel i/e loop port id). gchip_id will write later. */
        p_edit_db->gport = SYS_MAP_DRV_LPORT_TO_CTC_GPORT(gchip, lport);
        p_nh_param->oif.vid = 0;
        l3if_prop.vlan_ptr = MCHIP_CAP(SYS_CAP_L3IF_RSV_L3IF_ID) + MCHIP_CAP(SYS_CAP_L3IF_VLAN_PTR_BASE);
    }

    if(CTC_FLAG_ISSET(p_nh_srv6_param->flag, CTC_NH_SRV6_FLAG_REROUTE))
    {
        CTC_SET_FLAG(p_edit_db->flag, SYS_NH_SRV6_FLAG_REROUTE);
    }
    else
    {
        CTC_UNSET_FLAG(p_edit_db->flag, SYS_NH_SRV6_FLAG_REROUTE);
    }
    if (CTC_FLAG_ISSET(p_edit_db->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_NO_HW))
    {
        return CTC_E_NONE;
    }
    dsnh_param.dest_vlan_ptr = l3if_prop.vlan_ptr;
    if (p_nh_srv6_param->loop_nhid)
    {/* need loopback*/
        uint8 lb_with_ldp = CTC_FLAG_ISSET(p_nh_srv6_param->flag, CTC_NH_SRV6_FLAG_LB_WITH_LOGIC_DST_PORT);
        CTC_ERROR_RETURN(sys_usw_nh_add_loopback_l2edit(lchip, p_nh_srv6_param->loop_nhid, lb_with_ldp, TRUE,
                                                        &dsnh_param.l2edit_ptr));

        dsnh_param.loop_edit = 1;
        p_edit_db->outer_l2_edit_offset = dsnh_param.l2edit_ptr;
        CTC_SET_FLAG(p_edit_db->flag, SYS_NH_SRV6_FLAG_LOOP_NH);
        if (lb_with_ldp)
        {
            CTC_SET_FLAG(p_edit_db->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_LB_WITH_LOGIC_DST);
        }
    }
    else
    {
        /*1. Build dsL2Edit*/
        if (srh_aps_en)
        {
            /*do nothing*/
        }
        else if (p_edit_db->ecmp_if_id /*&& DRV_IS_TMM(lchip)*/)
        {
            dsnh_param.l2edit_ptr = g_usw_nh_master[lchip]->ecmp_if_resolved_l2edit;
            p_edit_db->outer_l2_edit_offset = dsnh_param.l2edit_ptr;
            dsnh_param.dest_vlan_ptr = MCHIP_CAP(SYS_CAP_L3IF_VLAN_PTR_BASE);
        }
        else if(!CTC_FLAG_ISSET(p_edit_db->flag, SYS_NH_SRV6_FLAG_REROUTE)
         || (DRV_FROM_AT(lchip) && p_edit_db->ecmp_if_id))
        {
            if(!CTC_FLAG_ISSET(p_edit_db->flag, SYS_NH_SRV6_FLAG_SRH_IS_LDP))
            {
                CTC_ERROR_GOTO(_sys_usw_nh_srv6_build_dsl2edit(lchip, p_nh_param, p_edit_db, &dsnh_param), ret, error_proc);
                if ((dsnh_param.l2edit_ptr != 0))
                {
                    CTC_SET_FLAG(p_edit_db->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L2EDIT);
                }
            }
        }
        else
        {
            /*for srv6 reroute, need pointer one l2editptr to adjust packet offset*/
            dsnh_param.l2edit_ptr = g_usw_nh_master[lchip]->srv6_resolved_l2edit;
            p_edit_db->outer_l2_edit_offset = dsnh_param.l2edit_ptr;
        }
        /*2. Build dsL3Edit*/
        CTC_ERROR_GOTO(_sys_usw_nh_srv6_build_dsl3edit(lchip, p_nh_param, p_edit_db, &dsnh_param), ret, error_proc);
        if (dsnh_param.l3edit_ptr != 0)
        {
            CTC_SET_FLAG(p_edit_db->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L3EDIT);
        }
        dsnh_param.inner_l2edit_ptr = ((p_nh_param->p_tnl) && (0 == p_edit_db->ecmp_if_id))? p_nh_param->p_tnl->l3edit_ptr : 0;
        dsnh_param.dvp_tbl_valid = CTC_FLAG_ISSET(p_edit_db->flag, SYS_NH_SRV6_FLAG_SRH_IS_LDP)?1:0;

        if (srh_aps_en)
        {
            dsnh_param.inner_l2edit_ptr = p_nh_param->p_tnl->arp_id;/*aps group id*/
            CTC_SET_FLAG(dsnh_param.flag, SYS_NH_PARAM_FLAG_L2EDIT_AS_APS_GROUP);
        }
    }

    if (p_nh_srv6_param->stats_id && (p_nh_srv6_param->flow_label_mode != CTC_NH_FLOW_LABEL_NONE)
        && CTC_FLAG_ISSET(p_edit_db->flag, SYS_NH_SRV6_FLAG_ENCAP))
    {
        CTC_ERROR_GOTO(sys_usw_flow_stats_get_statsptr(lchip, p_nh_srv6_param->stats_id,
                                                       &stats_ptr), ret, error_proc);
        dsnh_param.stats_ptr = stats_ptr;
    }

    if (CTC_FLAG_ISSET(p_nh_srv6_param->flag, CTC_NH_SRV6_FLAG_TTL_NO_DEC))
    {
        CTC_SET_FLAG(dsnh_param.flag, SYS_NH_PARAM_FLAG_ROUTE_NOTTL);
    }

    dsnh_param.dsnh_type = SYS_NH_PARAM_DSNH_TYPE_SRV6;
    dsnh_param.cid = p_nh_srv6_param->cid;
    if (p_nh_srv6_param->logic_port)
    {
        dsnh_param.logic_port = p_nh_srv6_param->logic_port;
        CTC_SET_FLAG(p_edit_db->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_LOGIC_PORT);
        p_edit_db->dest_logic_port = p_nh_srv6_param->logic_port;
    }
    dsnh_param.logic_port_check = CTC_FLAG_ISSET(p_nh_srv6_param->flag, CTC_NH_SRV6_FLAG_LOGIC_PORT_CHECK)? 1 : 0;
    if ((CTC_NH_SRV6_TYPE_E_INSERT == p_nh_srv6_param->srv6_type)
        || (CTC_NH_SRV6_TYPE_H_ENCAPS == p_nh_srv6_param->srv6_type)
        || (CTC_NH_SRV6_TYPE_H_INSERT == p_nh_srv6_param->srv6_type))
    {
        dsnh_param.strip_l2_hdr = 1;
    }
    if (CTC_FLAG_ISSET(p_nh_srv6_param->flag, CTC_NH_SRV6_FLAG_IP_BFD))
    {
        dsnh_param.strip_l2_hdr = 0;
    }
    if (CTC_NH_SRV6_TYPE_H_ENCAPS_L2 == p_nh_srv6_param->srv6_type)
    {
        CTC_SET_FLAG(dsnh_param.flag, SYS_NH_PARAM_FLAG_IP_TUNNEL_PLD_BRIDGE);
        if (p_nh_srv6_param->vlan_info)
        {
            dsnh_param.p_vlan_info = p_nh_srv6_param->vlan_info;
            CTC_SET_FLAG(p_edit_db->flag, SYS_NH_SRV6_FLAG_VLAN_EDIT);
            p_edit_db->cvlan_edit_type = p_nh_srv6_param->vlan_info->cvlan_edit_type;
            p_edit_db->svlan_edit_type = p_nh_srv6_param->vlan_info->svlan_edit_type;
            //p_edit_db->tpid_index = p_nh_srv6_param->vlan_info->svlan_tpid_index;

        }
        if (CTC_FLAG_ISSET(p_nh_srv6_param->flag, CTC_NH_SRV6_FLAG_HL2VPN))
        {
            CTC_UNSET_FLAG(p_edit_db->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HORIZON_SPLIT_EN);
            dsnh_param.hvpls = 1;
        }
        else
        {
            CTC_SET_FLAG(p_edit_db->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HORIZON_SPLIT_EN);
        }
    }

    if (p_nh_srv6_param->service_id && p_nh_srv6_param->logic_port)
    {
        /*Call QoS for binding service with logic Port*/
        CTC_ERROR_GOTO(sys_usw_qos_bind_service_logic_dstport(lchip, p_nh_srv6_param->service_id, p_nh_srv6_param->logic_port,p_edit_db->gport,p_edit_db->hdr.dsnh_offset), ret, error_proc);
        p_edit_db->service_id = p_nh_srv6_param->service_id;
    }

    if (CTC_FLAG_ISSET(p_edit_db->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W))
    {
        dsnh_param.dsnh_offset = p_edit_db->hdr.dsnh_offset;
        ret = sys_usw_nh_write_entry_dsnh8w(lchip, &dsnh_param);
        p_fwd_info->nexthop_ext = 1;
    }
    else
    {
        dsnh_param.dsnh_offset = p_edit_db->hdr.dsnh_offset;
        ret = sys_usw_nh_write_entry_dsnh4w(lchip, &dsnh_param);
    }

    if (ret)
    {
        goto error_proc;
    }

    return CTC_E_NONE;
error_proc:
    return ret;

}
STATIC int32
_sys_usw_nh_srv6_add_dsfwd(uint8 lchip, sys_nh_param_srv6_t* p_nh_param, sys_nh_info_com_t* p_com_db, uint8 is_dsfwd1)
{
    sys_nh_info_srv6_t* p_nh_info = NULL;
    sys_nh_param_dsfwd_t dsfwd_param;
    int32 ret = CTC_E_NONE;
    sys_nh_db_srh_t    *p_srh_tnl = NULL;

    p_nh_info     = (sys_nh_info_srv6_t*)(p_com_db);

    sal_memset(&dsfwd_param, 0, sizeof(sys_nh_param_dsfwd_t));
    dsfwd_param.is_mcast = FALSE;
    dsfwd_param.nexthop_ext = CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W);

    if (p_nh_param)
    {
        p_srh_tnl = p_nh_param->p_tnl;
    }
    else
    {
        p_srh_tnl = _sys_usw_nh_lkup_srh_id(lchip, p_nh_info->srh_id);
    }

    if (CTC_FLAG_ISSET(p_nh_info->flag, SYS_NH_SRV6_FLAG_REROUTE) || CTC_FLAG_ISSET(p_nh_info->flag, SYS_NH_SRV6_FLAG_LOOP_NH))
    {
        sys_usw_get_gchip_id(lchip, &dsfwd_param.dest_chipid);
    }
    else
    {
        dsfwd_param.dest_chipid = SYS_MAP_CTC_GPORT_TO_GCHIP(p_nh_info->gport);
    }

    if (CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_IS_APS_EN))
    {
        dsfwd_param.dest_id =  p_nh_info->gport;
        dsfwd_param.aps_type = CTC_APS_BRIDGE;
        if(p_nh_info->aps_xcon_met)
        {
             dsfwd_param.aps_type = 0;
             dsfwd_param.is_mcast = 1;
             if (p_nh_info->met_offset)
             {
                dsfwd_param.dest_id = p_nh_info->met_offset;
             }
             else
             {
                sys_usw_aps_get_met( lchip, p_nh_info->gport, &dsfwd_param.dest_id, NULL);
             }
        }
    }
    else if (p_srh_tnl && p_srh_tnl->arp_id &&
        !CTC_FLAG_ISSET(p_nh_info->flag, SYS_NH_SRV6_FLAG_REROUTE) &&
        !CTC_FLAG_ISSET(p_nh_info->flag, SYS_NH_SRV6_FLAG_LOOP_NH))
    {
        sys_nh_db_arp_t *p_arp = NULL;
        p_arp = (sys_usw_nh_lkup_arp_id(lchip, p_srh_tnl->arp_id));
        if (NULL == p_arp)
        {
            return CTC_E_NOT_EXIST;
        }
        dsfwd_param.dest_id = p_arp->destmap_profile;
        dsfwd_param.use_destmap_profile = 1;
    }
    else
    {
        dsfwd_param.dest_id = SYS_MAP_CTC_GPORT_TO_DRV_LPORT(p_nh_info->gport);
    }

    dsfwd_param.cut_through_dis = 1;/*disable cut through for non-ip packet when encap ip-tunnel*/
    dsfwd_param.drop_pkt = CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_IS_UNROV);
    dsfwd_param.dsnh_offset = p_nh_info->hdr.dsnh_offset;
    dsfwd_param.is_egress_edit =  CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_EGRESS_EDIT_MODE);
    /*alloc dsfwd offset and set hw*/
    CTC_ERROR_RETURN(_sys_usw_nh_add_dsfwd(lchip, p_com_db, &dsfwd_param, is_dsfwd1));
    return ret;
}

STATIC int32
_sys_usw_nh_update_srv6_fwd_to_spec(uint8 lchip, sys_nh_param_srv6_t* p_nhpara,
                                               sys_nh_info_srv6_t* p_nh_info)
{
    uint8 gchip = 0;
    sys_nh_param_special_t nh_para_spec;
    sys_com_ldp_update_t* update_param = p_nhpara->p_ldp_update;
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    sal_memset(&nh_para_spec, 0, sizeof(sys_nh_param_special_t));

    nh_para_spec.hdr.have_dsfwd = CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_DSFWD);
    nh_para_spec.hdr.have_dsfwd1 = CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_DSFWD1);
    if (nh_para_spec.hdr.have_dsfwd || nh_para_spec.hdr.have_dsfwd1)
    {
        nh_para_spec.hdr.nh_param_type = SYS_NH_TYPE_UNROV;
        nh_para_spec.hdr.is_internal_nh = TRUE;

       /*1.2 update dsfwd to unrov nh's dsfwd, write dsfwd*/
        CTC_ERROR_RETURN(sys_usw_nh_create_special_cb(lchip, (sys_nh_param_com_t*)(&nh_para_spec), (sys_nh_info_com_t*)(p_nh_info)));
    }

    CTC_SET_FLAG(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_IS_UNROV);

    _sys_usw_nh_free_srv6_resource(lchip, p_nh_info, NULL);

    /*2. update param*/
    sys_usw_get_gchip_id(lchip, &gchip);
    update_param->is_update = 1;
    update_param->is_srv6 = 1;
    update_param->nhid = p_nh_info->hdr.nh_id;
    update_param->destmap = SYS_ENCODE_DESTMAP(gchip, SYS_RSV_PORT_DROP_ID);
    update_param->dsnh_valid = 1;
    update_param->dsnh_offset = SYS_USW_DROP_NH_OFFSET;
    _sys_usw_nh_free_offset_by_nhinfo(lchip, SYS_NH_TYPE_SRV6, (sys_nh_info_com_t*)p_nh_info);

    sys_usw_nh_copy_nh_entry_flags2(lchip, p_nh_info->hdr.nh_entry_flags, &p_nh_info->hdr);
    return CTC_E_NONE;
}

STATIC int32
_sys_usw_nh_update_srv6_fwd_attr(uint8 lchip, sys_nh_param_srv6_t* p_nhpara,
                                            sys_nh_info_srv6_t* p_nh_info)
{
    sys_nh_info_srv6_t old_nh_info;
    int32 ret = 0;
    uint8 is_8w = 0;
    uint8 srv6_encap = 0;
    uint8 is_update = (p_nhpara->hdr.change_type != SYS_NH_CHANGE_TYPE_NULL);
    uint32 dsnh_offset = 0;
    uint32 cmd = 0;
    uint32 tbl_id = 0;
    DsNextHop8W_m data_w;
    sys_com_ldp_update_t* update_param = p_nhpara->p_ldp_update;

    if ((p_nhpara->p_srv6_nh_param->logic_port)
        || CTC_FLAG_ISSET(p_nhpara->p_srv6_nh_param->flag, CTC_NH_SRV6_FLAG_LOGIC_PORT_CHECK)
        || (p_nhpara->p_srv6_nh_param->vlan_info != NULL))
    {
        is_8w = 1;
    }

    if ((CTC_NH_SRV6_TYPE_E_ENCAPS == p_nhpara->p_srv6_nh_param->srv6_type)
        || (CTC_NH_SRV6_TYPE_H_ENCAPS == p_nhpara->p_srv6_nh_param->srv6_type)
    || (CTC_NH_SRV6_TYPE_H_ENCAPS_L2 == p_nhpara->p_srv6_nh_param->srv6_type))
    {
        srv6_encap = 1;
    }
    if (srv6_encap && g_usw_nh_master[lchip]->cid_use_4w &&
        p_nhpara->p_srv6_nh_param->stats_id && (p_nhpara->p_srv6_nh_param->flow_label_mode != CTC_NH_FLOW_LABEL_NONE))
    {
        is_8w = 1;
    }

    if ((0 == srv6_encap)
        && (CTC_NH_DSCP_SELECT_MAP == p_nhpara->p_srv6_nh_param->dscp_select))
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] Not support dscp select map for insertion \n");
        return CTC_E_INVALID_PARAM;
    }

    if ((0 == CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W)) && is_8w
        && (!CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_IS_UNROV)))
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] Should use DsNexthop8W table \n");
        return CTC_E_INVALID_CONFIG;
    }

    if (is_update)
    {
        /*store nh old data, for recover*/
        tbl_id = CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W)?DsNextHop8W_t:DsNextHop4W_t;
        sal_memset(&data_w, 0, sizeof(DsNextHop8W_m));
        dsnh_offset = p_nh_info->hdr.dsnh_offset;
        cmd = DRV_IOR(tbl_id, DRV_ENTRY_FLAG);
        DRV_IOCTL(lchip, dsnh_offset, cmd, &data_w);

        sal_memcpy(&old_nh_info, p_nh_info, sizeof(sys_nh_info_srv6_t));
        sal_memset(p_nh_info, 0, sizeof(sys_nh_info_srv6_t));
        sys_usw_nh_copy_nh_entry_flags(lchip, &old_nh_info.hdr, &p_nh_info->hdr);
        p_nh_info->bind_data = old_nh_info.bind_data;
        p_nh_info->ipsa_index =(old_nh_info.flag & SYS_NH_SRV6_FLAG_HAVE_IPSA) ? old_nh_info.ipsa_index:0xFF;
    }
    CTC_ERROR_GOTO(sys_usw_nh_create_srv6_cb(lchip, (sys_nh_param_com_t*)p_nhpara,
                                             (sys_nh_info_com_t*)p_nh_info), ret, error_proc);
    /*for update free resource here*/
    if (is_update)
    {
        sys_nh_db_srh_t* p_srh_tnl = NULL;
        _sys_usw_nh_free_srv6_resource(lchip, &old_nh_info, p_nh_info);

        p_srh_tnl = _sys_usw_nh_lkup_srh_id(lchip, p_nh_info->srh_id);
        /*update param*/
        update_param->is_update = 1;
        update_param->is_srv6 = 1;
        update_param->nhid = p_nh_info->hdr.nh_id;
        update_param->ecmp_gid = p_nh_info->ecmp_if_id;
        update_param->ldp = p_nh_info->srh_id?p_nh_info->srh_id:SYS_COM_LDP_ECMP_ID(p_nh_info->ecmp_if_id);
        update_param->ldp = SYS_COM_LDP_SRH_ID(update_param->ldp);
        if(p_nh_info->ecmp_if_id)/*ldp ecmp en or ecmp interface*/
        {
            update_param->destmap = SYS_ENCODE_ECMP_DESTMAP(p_nh_info->ecmp_if_id);
        }
        else if (CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_IS_APS_EN))
        {
            update_param->aps_en = 1;
            update_param->destmap =  p_nh_info->gport;
        }
        else if (p_srh_tnl && p_srh_tnl->arp_id &&
            !CTC_FLAG_ISSET(p_nh_info->flag, SYS_NH_SRV6_FLAG_REROUTE) &&
            !CTC_FLAG_ISSET(p_nh_info->flag, SYS_NH_SRV6_FLAG_LOOP_NH))
        {
            sys_nh_db_arp_t *p_arp = NULL;
            p_arp = sys_usw_nh_lkup_arp_id(lchip, p_srh_tnl->arp_id);
            if(p_arp)
            {
                update_param->destmap = SYS_ENCODE_ARP_DESTMAP(p_arp->destmap_profile);
            }
        }
        else
        {
            update_param->destmap = SYS_ENCODE_DESTMAP(CTC_MAP_GPORT_TO_GCHIP(p_nh_info->gport), CTC_MAP_GPORT_TO_LPORT(p_nh_info->gport));
        }
        if(SYS_NH_CHANGE_TYPE_UNROV_TO_FWD == p_nhpara->hdr.change_type)
        {
            update_param->dsnh_valid = 1;
            update_param->dsnh_offset = p_nh_info->hdr.dsnh_offset;
            update_param->nexthop_ext = CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W);
            update_param->bypass_igr_edit = CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_EGRESS_EDIT_MODE);
        }
    }
    return CTC_E_NONE;
error_proc:
    if (is_update)
    {
        sal_memcpy( p_nh_info, &old_nh_info, sizeof(sys_nh_info_srv6_t));
        tbl_id = CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W)?DsNextHop8W_t:DsNextHop4W_t;
        dsnh_offset = p_nh_info->hdr.dsnh_offset;
        cmd = DRV_IOW(tbl_id, DRV_ENTRY_FLAG);
        DRV_IOCTL(lchip, dsnh_offset, cmd, &data_w);
    }
    return ret;
}

/* Used to update mpls nexthop when tunnel arp update */
STATIC int32
_sys_usw_nh_srv6_update_arp_cb(uint8 lchip, sys_nh_info_srv6_t* p_nhinfo, uint32 arp_id, sys_com_ldp_update_t* update_param)
{
    sys_l3if_prop_t l3if_prop;
    sys_nh_db_arp_t* p_arp = NULL;
    uint32 nexthop_ptr = 0;
    uint32 cmd = 0;
    DsL3EditAddIp6Sr_m dsaddip6sr;
    DsL3EditRwIp6Sr_m dsrwip6sr;
    DsNextHop8W_m dsnh8w;
    uint32 tbl_type = 0;
    sys_nh_info_ext_t* p_nh_info_ext = NULL;
    uint8 l2_nexthop_ptr_valid = 0;
    uint32 l2_edit_ptr = 0;
    sys_nh_db_srh_t    *p_srh_tnl = NULL;

    if (!p_nhinfo)
    {
        return CTC_E_NONE;
    }

    if (CTC_FLAG_ISSET(p_nhinfo->flag, SYS_NH_SRV6_FLAG_REROUTE) || CTC_FLAG_ISSET(p_nhinfo->flag, SYS_NH_SRV6_FLAG_LOOP_NH))
    {
        return CTC_E_NONE;
    }
    /*1. get arp id info*/
    p_arp = (sys_usw_nh_lkup_arp_id(lchip, arp_id));
    if (NULL == p_arp)
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Entry not exist \n");
        return CTC_E_NOT_EXIST;
    }
    l3if_prop.l3if_id = p_arp->l3if_id;
    if (l3if_prop.l3if_id)
    {
        CTC_ERROR_RETURN(sys_usw_l3if_get_l3if_info(lchip, 1, &l3if_prop));
    }
    /*2.update destvlanptr & l2editptr*/
    nexthop_ptr = p_nhinfo->hdr.dsnh_offset;
    tbl_type = CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W) ? SYS_NH_ENTRY_TYPE_NEXTHOP_8W : SYS_NH_ENTRY_TYPE_NEXTHOP_4W;
    CTC_ERROR_RETURN(sys_usw_nh_get_asic_table(lchip, tbl_type, nexthop_ptr, &dsnh8w));
    SetDsNextHop4W(V, destVlanPtr_f, &dsnh8w, l3if_prop.vlan_ptr);
    CTC_ERROR_RETURN(sys_usw_nh_set_asic_table(lchip, tbl_type, nexthop_ptr, &dsnh8w));

    /*When arp offset more than 2k, should set nexthopPtrValid 0*/
    l2_edit_ptr = p_arp->offset;
    l2_nexthop_ptr_valid = 1;
    if (l2_edit_ptr && (l2_edit_ptr >= MCHIP_CAP(SYS_CAP_NH_OUTER_L2_EDIT_NUM)))
    {
        l2_nexthop_ptr_valid = 0;
        l2_edit_ptr = l2_edit_ptr - MCHIP_CAP(SYS_CAP_NH_OUTER_L2_EDIT_NUM);
    }
    p_srh_tnl = _sys_usw_nh_lkup_srh_id(lchip, p_nhinfo->srh_id);
    if (p_srh_tnl && CTC_FLAG_ISSET(p_nhinfo->flag, SYS_NH_SRV6_FLAG_ENCAP))
    {
        if (p_srh_tnl->num)
        {
            cmd = DRV_IOR(DsL3EditAddIp6Sr_t, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, p_nhinfo->dsl3edit_offset, cmd, &dsaddip6sr));
            SetDsL3EditAddIp6Sr(V, outerEditPtr_f, &dsaddip6sr, l2_edit_ptr);
            SetDsL3EditAddIp6Sr(V, nextEditPtrValid_f, &dsaddip6sr, l2_nexthop_ptr_valid);
            cmd = DRV_IOW(DsL3EditAddIp6Sr_t, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, p_nhinfo->dsl3edit_offset, cmd, &dsaddip6sr));
        }
        else
        {
            cmd = DRV_IOR(DsL3EditAddIp6_t, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, p_nhinfo->dsl3edit_offset, cmd, &dsaddip6sr));
            SetDsL3EditAddIp6(V, outerEditPtr_f, &dsaddip6sr, l2_edit_ptr);
            SetDsL3EditAddIp6(V, nextEditPtrValid_f, &dsaddip6sr, l2_nexthop_ptr_valid);
            cmd = DRV_IOW(DsL3EditAddIp6_t, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, p_nhinfo->dsl3edit_offset, cmd, &dsaddip6sr));
        }
    }
    else
    {
        cmd = DRV_IOR(DsL3EditRwIp6Sr_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip,  p_nhinfo->dsl3edit_offset, cmd, &dsrwip6sr));
        SetDsL3EditRwIp6Sr(V, outerEditPtr_f, &dsrwip6sr, l2_edit_ptr);
        SetDsL3EditRwIp6Sr(V, nextEditPtrValid_f, &dsaddip6sr, l2_nexthop_ptr_valid);
        cmd = DRV_IOW(DsL3EditRwIp6Sr_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip,  p_nhinfo->dsl3edit_offset, cmd, &dsrwip6sr));
    }
    /*3. Update destmap profile ID*/
    if (CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_DSFWD))
    {
        uint32 dsfwd_offset = 0;
        DsFwd_m dsfwd;
        DsFwdHalf_m dsfwd_half;

        dsfwd_offset = p_nhinfo->hdr.dsfwd_offset;
        CTC_ERROR_RETURN(sys_usw_nh_get_asic_table(lchip, SYS_NH_ENTRY_TYPE_FWD, dsfwd_offset, &dsfwd));
        if (GetDsFwd(V, isHalf_f, &dsfwd))
        {
            if (dsfwd_offset % 2 == 0)
            {
                GetDsFwdDualHalf(A, g_0_dsFwdHalf_f,   &dsfwd,   &dsfwd_half);
            }
            else
            {
                GetDsFwdDualHalf(A, g_1_dsFwdHalf_f,   &dsfwd,   &dsfwd_half);
            }
            SetDsFwdHalf(V, destMap_f, &dsfwd_half,   SYS_ENCODE_ARP_DESTMAP(p_arp->destmap_profile));

            if (dsfwd_offset % 2 == 0)
            {
                SetDsFwdDualHalf(A, g_0_dsFwdHalf_f,   &dsfwd,   &dsfwd_half);
            }
            else
            {
                SetDsFwdDualHalf(A, g_1_dsFwdHalf_f,   &dsfwd,   &dsfwd_half);
            }
        }
        else
        {
            SetDsFwd(V, destMap_f, &dsfwd, SYS_ENCODE_ARP_DESTMAP(p_arp->destmap_profile));
        }

        CTC_ERROR_RETURN(sys_usw_nh_set_asic_table(lchip, SYS_NH_ENTRY_TYPE_FWD, dsfwd_offset, &dsfwd));

    }

    /*using cb to update fwd table info*/
    update_param->is_update = 1;
    update_param->is_srv6 = 1;
    
    if (CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_IS_APS_EN))
    {
        update_param->aps_en = 1;
        update_param->destmap =  p_nhinfo->gport;
    }
    else if (p_srh_tnl && p_srh_tnl->arp_id &&
        !CTC_FLAG_ISSET(p_nhinfo->flag, SYS_NH_SRV6_FLAG_REROUTE) &&
        !CTC_FLAG_ISSET(p_nhinfo->flag, SYS_NH_SRV6_FLAG_LOOP_NH))
    {
        update_param->destmap = SYS_ENCODE_ARP_DESTMAP(p_arp->destmap_profile);
    }
    else
    {
        update_param->destmap = SYS_ENCODE_DESTMAP(CTC_MAP_GPORT_TO_GCHIP(p_nhinfo->gport), CTC_MAP_GPORT_TO_LPORT(p_nhinfo->gport));
    }

    if (CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_DSFWD1))
    {
        uint32 dsfwd_offset = 0;
        DsFwd_m dsfwd;
        DsFwdHalf_m dsfwd_half;

        dsfwd_offset = p_nhinfo->hdr.dsfwd1_offset;
        CTC_ERROR_RETURN(sys_usw_nh_get_asic_table(lchip, SYS_NH_ENTRY_TYPE_FWD1, dsfwd_offset, &dsfwd));
        if (GetDsFwd(V, isHalf_f, &dsfwd))
        {
            if (dsfwd_offset % 2 == 0)
            {
                GetDsFwdDualHalf(A, g_0_dsFwdHalf_f,   &dsfwd,   &dsfwd_half);
            }
            else
            {
                GetDsFwdDualHalf(A, g_1_dsFwdHalf_f,   &dsfwd,   &dsfwd_half);
            }
            SetDsFwdHalf(V, destMap_f, &dsfwd_half,   SYS_ENCODE_ARP_DESTMAP(p_arp->destmap_profile));

            if (dsfwd_offset % 2 == 0)
            {
                SetDsFwdDualHalf(A, g_0_dsFwdHalf_f,   &dsfwd,   &dsfwd_half);
            }
            else
            {
                SetDsFwdDualHalf(A, g_1_dsFwdHalf_f,   &dsfwd,   &dsfwd_half);
            }
        }
        else
        {
            SetDsFwd(V, destMap_f, &dsfwd, SYS_ENCODE_ARP_DESTMAP(p_arp->destmap_profile));
        }

        CTC_ERROR_RETURN(sys_usw_nh_set_asic_table(lchip, SYS_NH_ENTRY_TYPE_FWD1, dsfwd_offset, &dsfwd));
    }
    CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo_ext_by_nhid(lchip, p_nhinfo->hdr.nh_id, &p_nh_info_ext, 0));
    p_nhinfo->gport = p_arp->gport;
    p_nhinfo->l3ifid = p_arp->l3if_id;
    if (p_nh_info_ext && p_nh_info_ext->ecmp_list)
    {
        CTC_ERROR_RETURN(sys_usw_nh_update_ecmp_member(lchip, p_nhinfo->hdr.nh_id, SYS_NH_CHANGE_TYPE_UPDATE_FWD_ATTR, p_nh_info_ext->ecmp_list));
    }
    if (p_nh_info_ext && p_nh_info_ext->aps_list)
    {
        sys_nh_ref_list_node_t* p_ref_node = NULL;
        sys_nh_info_com_t* p_nh_com = NULL;

        p_ref_node = p_nh_info_ext->aps_list;
        while (p_ref_node)
        {
            p_nh_com = p_ref_node->p_ref_nhinfo;
            CTC_ERROR_RETURN(sys_usw_nh_update_aps_by_nh(lchip, p_nh_com->hdr.nh_id, p_nhinfo->hdr.nh_id));
            p_ref_node = p_ref_node->p_next;
        }
    }
    return CTC_E_NONE;
}

STATIC int32
_sys_usw_nh_srv6_sid_num_check(uint8 lchip, ctc_nh_srv6_param_t* p_nh_srv6_param, sys_nh_db_srh_t *p_srh_tnl, sys_nh_info_srv6_t* p_nhdb)
{
    ipv6_addr_t vpn_sid_tmp;
    uint8 max_num = 0;

    sal_memset(&vpn_sid_tmp, 0, sizeof(ipv6_addr_t));

    if ((!CTC_FLAG_ISSET(p_srh_tnl->flag, SYS_NH_SRH_FLAG_DENY_REPLACE_IPDA) && !(CTC_NH_SRV6_TYPE_E_INSERT == p_nh_srv6_param->srv6_type) && sal_memcmp(p_nh_srv6_param->vpn_sid, vpn_sid_tmp, sizeof(ipv6_addr_t))) ||
    (CTC_NH_SRV6_TYPE_H_INSERT == p_nh_srv6_param->srv6_type))
    {
        max_num = SYS_NH_SRV6_MAX_SID_NUM - 1;
    }
    else
    {
        max_num = SYS_NH_SRV6_MAX_SID_NUM;
    }

    if (max_num < p_srh_tnl->num)
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] The sid number of srh exceeds the max number\n");
        return CTC_E_INVALID_PARAM;
    }

    if (((CTC_NH_SRV6_TYPE_E_INSERT == p_nh_srv6_param->srv6_type)
    || (CTC_NH_SRV6_TYPE_H_INSERT == p_nh_srv6_param->srv6_type)
    ||(0 != p_nh_srv6_param->loop_nhid)) && !p_srh_tnl->num && !CTC_FLAG_ISSET(p_srh_tnl->flag, SYS_NH_SRH_FLAG_APS)
    && (!(CTC_FLAG_ISSET(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_NO_HW))))
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " The number of SID do not be zero! \n");
        return CTC_E_INVALID_CONFIG;
    }

    if ((1 == p_srh_tnl->num) && (1 == p_srh_tnl->is_reduce) && !CTC_FLAG_ISSET(p_nh_srv6_param->flag, CTC_NH_SRV6_FLAG_REROUTE)
        && (0 == sal_memcmp(p_nh_srv6_param->vpn_sid, vpn_sid_tmp, sizeof(ipv6_addr_t))))
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " The reduce mode , number of SID must over 1! \n");
        return CTC_E_INVALID_CONFIG;
    }

    return CTC_E_NONE;
}

int32
sys_usw_nh_add_srh_id(uint8 lchip, uint32* srh_id, ctc_nh_srh_edit_param_t* p_nh_param)
{
    sys_nh_db_srh_t* srh_db = NULL;
    sys_usw_nh_master_t* p_master = g_usw_nh_master[lchip];
    int32 ret = CTC_E_NONE;

    CTC_PTR_VALID_CHECK(srh_id);
    CTC_PTR_VALID_CHECK(p_nh_param);
    CTC_MIN_VALUE_CHECK(*srh_id, 1);
    CTC_MAX_VALUE_CHECK(*srh_id, SYS_USW_MAX_SRH_ID);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_PARAM, "srh_id = %d, num = %d, reduce = %d\n", *srh_id, p_nh_param->num, p_nh_param->reduce);
    CTC_ERROR_RETURN(_sys_usw_nh_srv6_srh_param_chk(lchip, p_nh_param));

    if(*srh_id > p_master->max_srh_id)
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Exceed max srh id %u \n", p_master->max_srh_id);
        return CTC_E_INVALID_PARAM;
    }

    srh_db = _sys_usw_nh_lkup_srh_id(lchip, *srh_id);
    if(srh_db)
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] SRH exist!\n");
        return CTC_E_EXIST;
    }

    srh_db  = (sys_nh_db_srh_t*)mem_malloc(MEM_NEXTHOP_MODULE, sizeof(sys_nh_db_srh_t));
    if (NULL == srh_db)
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] No memory \n");
        ret = CTC_E_NO_MEMORY;
        goto error0;
    }
    sal_memset(srh_db, 0, sizeof(sys_nh_db_srh_t));
    srh_db->pd = (sys_nh_db_srh_pdata_t*)mem_malloc(MEM_NEXTHOP_MODULE, sizeof(sys_nh_db_srh_pdata_t));
    if (!srh_db->pd)
    {
        ret =  CTC_E_NO_MEMORY;
        goto error1;
    }
    sal_memset(srh_db->pd, 0, sizeof(sys_nh_db_srh_pdata_t));

    srh_db->srh_id = *srh_id;
    srh_db->ldp = p_nh_param->ldp;
    if (p_nh_param->arp_id)
    {
        sys_nh_info_arp_param_t arp_parm;
        sal_memset(&arp_parm, 0, sizeof(sys_nh_info_arp_param_t));
        arp_parm.nh_entry_type  = SYS_NH_TYPE_SRV6;
        CTC_ERROR_GOTO(sys_usw_nh_bind_arp_cb(lchip, &arp_parm, p_nh_param->arp_id), ret, error1);
        srh_db->arp_id = p_nh_param->arp_id;
    }
    if(p_nh_param->num)
    {
        uint32 l3edit_ptr = 0;
        CTC_ERROR_GOTO(sys_usw_nh_offset_alloc(lchip, SYS_NH_ENTRY_TYPE_L3EDIT_SRH +  SYS_NH_TYPE_STEP_TO_INNER, 1, &l3edit_ptr), ret, error2);
        srh_db->l3edit_ptr = l3edit_ptr;
        CTC_ERROR_GOTO(_sys_usw_nh_srv6_build_srh(lchip, p_nh_param, srh_db), ret, error3);
    }
    if (FALSE == ctc_hash_insert(p_master->srh_id_hash, srh_db))
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] No memory \n");
        ret = CTC_E_NO_MEMORY;
        goto error3;
    }
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_SRH, 1);
    return CTC_E_NONE;
error3:
	if(p_nh_param->num)
    {
        sys_usw_nh_offset_free(lchip, SYS_NH_ENTRY_TYPE_L3EDIT_SRH +  SYS_NH_TYPE_STEP_TO_INNER, 1, srh_db->l3edit_ptr);
    }
error2:
    if (p_nh_param->arp_id)
    {
        sys_usw_nh_unbind_arp_cb(lchip, p_nh_param->arp_id, 0, NULL);
    }
error1:
    if(srh_db->pd)
    {
        mem_free(srh_db->pd);
    }
    mem_free(srh_db);
error0:

    return ret;
}

int32
sys_usw_nh_remove_srh_id(uint8 lchip, uint32 srh_id)
{
    sys_nh_db_srh_t* srh_db = NULL;
    sys_ldp_t sys_ldp;

    sal_memset(&sys_ldp, 0, sizeof(sys_ldp_t));

    srh_db = _sys_usw_nh_lkup_srh_id(lchip, srh_id);
    if (NULL == srh_db)
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] SRH not exist!\n");
        return CTC_E_NOT_EXIST;
    }

    if (CTC_FLAG_ISSET(srh_db->flag, SYS_NH_SRH_FLAG_APS))
    {
        return CTC_E_INVALID_CONFIG;
    }

    if (srh_db->pd->nh_list || srh_db->pd->p_srh_list || srh_db->pd->ecmp_list)
    {
        return CTC_E_IN_USE;
    }
    if (srh_db->ldp)
    {
        /*used for Write DsLogicDestPort*/
        sys_ldp.l3edit_ptr   = 0;

        CTC_ERROR_RETURN(sys_usw_nh_write_asic_table(lchip, SYS_NH_ENTRY_TYPE_LOGIC_DEST_PORT, srh_db->ldp, &sys_ldp));
    }
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_SRH, 1);
    sys_usw_nh_offset_free(lchip, SYS_NH_ENTRY_TYPE_L3EDIT_SRH +  SYS_NH_TYPE_STEP_TO_INNER, 1, srh_db->l3edit_ptr);
    ctc_hash_remove(g_usw_nh_master[lchip]->srh_id_hash, srh_db);

    if (srh_db->arp_id)
    {
        sys_usw_nh_unbind_arp_cb(lchip, srh_db->arp_id, 0, NULL);
    }
    mem_free(srh_db->pd);
    mem_free(srh_db);
    return CTC_E_NONE;
}

int32
sys_usw_nh_update_srh_id(uint8 lchip, uint32 srh_id, ctc_nh_srh_edit_param_t* p_nh_param, sys_com_ldp_update_t* update_param)
{
    sys_nh_db_srh_t* srh_db = NULL;
    uint8 arp_update = 0;
    uint8 ldp_update = 0;

    CTC_PTR_VALID_CHECK(p_nh_param);
    srh_db = _sys_usw_nh_lkup_srh_id(lchip, srh_id);
    if (NULL == srh_db)
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] SRH not exist!\n");
        return CTC_E_NOT_EXIST;
    }

    if (CTC_FLAG_ISSET(srh_db->flag, SYS_NH_SRH_FLAG_APS))
    {
        return CTC_E_INVALID_CONFIG;
    }

    CTC_ERROR_RETURN(_sys_usw_nh_srv6_srh_param_chk(lchip, p_nh_param));

    if (CTC_FLAG_ISSET(srh_db->flag, SYS_NH_SRH_FLAG_DENY_REPLACE_IPDA) != CTC_FLAG_ISSET(p_nh_param->flag, CTC_NH_SRH_FLAG_DENY_REPLACE_IPDA))
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] SRH not support update whether deny replace ipda!\n");
        return CTC_E_INVALID_CONFIG;
    }

    if ((!srh_db->num && p_nh_param->num) || (srh_db->num && !p_nh_param->num))
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] No support for updating with or whitout sid list!\n");
        return CTC_E_INVALID_CONFIG;
    }
    else if (p_nh_param->num)
    {
        sys_nh_ref_list_node_t* p_curr = NULL;
        sys_nh_tunnel_ref_list_node_t* p_srh_list = NULL;
        sys_nh_info_srv6_t* p_nh_info_srv6 = NULL;
        sys_nh_db_srh_t* p_nh_db_srh = NULL;

        p_curr = srh_db->pd->nh_list;

        while (p_curr)
        {
            p_nh_info_srv6 = (sys_nh_info_srv6_t*)p_curr->p_ref_nhinfo;

            if (p_nh_info_srv6->replace_last && (p_nh_param->num > (SYS_NH_SRV6_MAX_SID_NUM - 1)))
            {
                SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] SID num exceed max!\n");
                return CTC_E_INVALID_CONFIG;
            }

            p_curr = p_curr->p_next;
        }

        p_srh_list = srh_db->pd->p_srh_list;

        while (p_srh_list)
        {
            p_nh_db_srh = (sys_nh_db_srh_t*)p_srh_list->p_ref_node;

            p_curr = p_nh_db_srh->pd->nh_list;
            while (p_curr)
            {
                p_nh_info_srv6 = (sys_nh_info_srv6_t*)p_curr->p_ref_nhinfo;

                if (p_nh_info_srv6->replace_last && (p_nh_param->num > (SYS_NH_SRV6_MAX_SID_NUM - 1)))
                {
                    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] SID num exceed max!\n");
                    return CTC_E_INVALID_CONFIG;
                }

                p_curr = p_curr->p_next;
            }

            p_srh_list = p_srh_list->p_next;
        }
    }

    if ((!srh_db->arp_id && p_nh_param->arp_id) || (srh_db->arp_id && !p_nh_param->arp_id))
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] No support for updating with or whitout ARP!\n");
        return CTC_E_INVALID_CONFIG;
    }

    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_SRH, 1);

    if (srh_db->arp_id != p_nh_param->arp_id)
    {
        arp_update = 1;
    }
    if (srh_db->ldp != p_nh_param->ldp)
    {
        ldp_update = 1;
    }

    /*Update Arp ID*/
    if (arp_update || ldp_update)
    {
        sys_nh_ref_list_node_t* p_curr = NULL;
        sys_nh_tunnel_ref_list_node_t* p_tunnel_curr = NULL;
        sys_nh_info_arp_param_t arp_parm;
        sys_nh_db_srh_t* p_srh_aps = NULL;
        ctc_nh_aps_param_t aps_param;
        uint32 arp_id_tmp = srh_db->arp_id;
        sal_memset(&arp_parm, 0, sizeof(sys_nh_info_arp_param_t));

        SYS_USW_REGISTER_WB_SYNC_EN(SYS_PP_BASE(lchip), CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_INFO_COM, 1);

        /* 1. update srv6 nexthop */
        p_curr = srh_db->pd->nh_list;
        if (arp_update)
        {
            arp_parm.nh_entry_type  = SYS_NH_TYPE_SRV6;
            CTC_ERROR_RETURN(sys_usw_nh_bind_arp_cb(lchip, &arp_parm, p_nh_param->arp_id));
            srh_db->arp_id = p_nh_param->arp_id;

            srh_db->ldp = p_nh_param->ldp;
            while (p_curr)
            {
                _sys_usw_nh_srv6_update_arp_cb(lchip, (sys_nh_info_srv6_t*)p_curr->p_ref_nhinfo, p_nh_param->arp_id, update_param);
                p_curr = p_curr->p_next;
            }
        }
        /*2. update ecmp list*/
        if (NULL != srh_db->pd->ecmp_list)
        {
            sys_usw_nh_update_ecmp_member(lchip, srh_id, SYS_NH_CHANGE_TYPE_UPDATE_SRH, srh_db->pd->ecmp_list);
        }

        /* 3. update srh aps */
        if (arp_update)
        {
            p_tunnel_curr = srh_db->pd->p_srh_list;
            sal_memset(&aps_param, 0, sizeof(aps_param));
            aps_param.type = 1;
            while (p_tunnel_curr)
            {
                p_srh_aps = (sys_nh_db_srh_t*)p_tunnel_curr->p_ref_node;
                aps_param.aps_group_id = p_srh_aps->arp_id;
                aps_param.w_nhid = p_srh_aps->l3edit_ptr;
                aps_param.p_nhid = p_srh_aps->p_srh_id;
                sys_usw_nh_update_srh_aps(lchip, p_srh_aps->srh_id, &aps_param);
                p_tunnel_curr = p_tunnel_curr->p_next;
            }
        }
        if (arp_update)
        {
            sys_usw_nh_unbind_arp_cb(lchip, arp_id_tmp, 0, NULL);
        }
    }

    /*Update SRH HW*/
    if (p_nh_param->num)
    {
        _sys_usw_nh_srv6_build_srh(lchip, p_nh_param, srh_db);
    }

    /*update ldp*/
    if (srh_db->ldp != p_nh_param->ldp)
    {
        srh_db->ldp = p_nh_param->ldp;

        /*update srh ecmp(second level)*/
        sys_usw_nh_update_ecmp_member(lchip, srh_id, SYS_NH_CHANGE_TYPE_UPDATE_SRH, srh_db->pd->ecmp_list);

    }

    return CTC_E_NONE;
}

int32
sys_usw_nh_create_srv6_cb(uint8 lchip, sys_nh_param_com_t* p_com_nh_para, sys_nh_info_com_t* p_com_db)
{
    sys_nh_param_srv6_t* p_nh_param = NULL;
    ctc_nh_srv6_param_t* p_nh_srv6_param = NULL;
    sys_nh_info_srv6_t* p_nhdb = NULL;
    sys_nh_db_srh_t    *p_srh_tnl = NULL;
    sys_nh_info_ecmp_t *p_ecmp_nh = NULL;
    sys_nh_param_dsfwd_t dsfwd_param;
    int32 ret = 0;

    sal_memset(&dsfwd_param, 0, sizeof(sys_nh_param_dsfwd_t));

    p_nh_param = (sys_nh_param_srv6_t*)(p_com_nh_para);
    p_nh_srv6_param = p_nh_param->p_srv6_nh_param;
    p_nhdb     = (sys_nh_info_srv6_t*)(p_com_db);
    p_nhdb->hdr.nh_entry_type = SYS_NH_TYPE_SRV6;
    p_nhdb->hdr.nh_id = p_nh_param->hdr.nhid;

    CTC_MAX_VALUE_CHECK(p_nh_srv6_param->ecn_select, (MAX_CTC_NH_ECN_SELECT_MODE - 1));
    if (p_nh_srv6_param->logic_port && (p_nh_srv6_param->logic_port > MCHIP_CAP(SYS_CAP_MAX_LOGIC_PORT)))
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Invalid logic port\n");
        return CTC_E_INVALID_PORT;
    }

    if (p_nh_srv6_param->service_id && (0 == p_nh_srv6_param->logic_port ))
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Need logic port\n");
        return CTC_E_INVALID_PARAM;
    }

    if ((CTC_NH_SRV6_TYPE_E_ENCAPS == p_nh_srv6_param->srv6_type) && (0 == p_nh_srv6_param->loop_nhid))
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Need loop_nhid\n");
        return CTC_E_INVALID_CONFIG;
    }

    if (((CTC_NH_SRV6_TYPE_E_INSERT == p_nh_srv6_param->srv6_type)
        || (CTC_NH_SRV6_TYPE_H_INSERT == p_nh_srv6_param->srv6_type))
    && (CTC_FLAG_ISSET(p_nh_srv6_param->flag, CTC_NH_SRV6_FLAG_MTU_CHECK)))
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Not support MTU check\n");
        return CTC_E_INVALID_CONFIG;
    }

    if (((CTC_NH_SRV6_TYPE_E_INSERT == p_nh_srv6_param->srv6_type)
        || (CTC_NH_SRV6_TYPE_H_INSERT == p_nh_srv6_param->srv6_type)) && (CTC_NH_DSCP_SELECT_MAP == p_nh_srv6_param->dscp_select))
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] Not support dscp select map for insertion \n");
        return CTC_E_INVALID_CONFIG;
    }

    if (p_nh_param->oif.ecmp_if_id > 0)
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Not support ecmp interface\n");
        return CTC_E_NOT_SUPPORT;
    }
    if (((p_nh_srv6_param->stats_id && p_nh_srv6_param->cid) ||(p_nh_param->p_srv6_nh_param->cid && !g_usw_nh_master[lchip]->cid_use_4w))
        && (!CTC_FLAG_ISSET(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W)))
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Cnnot support stats and cid in 4w mode \n");
        return CTC_E_INVALID_CONFIG;
    }

    if (p_nh_srv6_param->vlan_info != NULL)
    {
        if (CTC_FLAG_ISSET(p_nh_srv6_param->vlan_info->edit_flag, CTC_VLAN_EGRESS_EDIT_OUPUT_CVID_VALID))
        {
            CTC_VLAN_RANGE_CHECK(p_nh_srv6_param->vlan_info->output_cvid);
        }
        if (CTC_FLAG_ISSET(p_nh_srv6_param->vlan_info->edit_flag, CTC_VLAN_EGRESS_EDIT_OUPUT_SVID_VALID))
        {
            CTC_VLAN_RANGE_CHECK(p_nh_srv6_param->vlan_info->output_svid);
        }
    }

    /* i. get srh soft table */
    if (!CTC_FLAG_ISSET(p_nh_srv6_param->flag, CTC_NH_SRV6_FLAG_SRH_ECMP) &&p_nh_srv6_param->srh_id)
    {
        p_srh_tnl = _sys_usw_nh_lkup_srh_id(lchip, p_nh_srv6_param->srh_id);
        if (NULL == p_srh_tnl)
        {
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] SRH not exist!\n");
           return CTC_E_NOT_EXIST;
        }

        /* check sid num */
        if (CTC_FLAG_ISSET(p_srh_tnl->flag, SYS_NH_SRH_FLAG_APS))
        {
            sys_nh_db_srh_t *p_srh_tnl_w = NULL;
            sys_nh_db_srh_t *p_srh_tnl_p = NULL;

            p_srh_tnl_w = _sys_usw_nh_lkup_srh_id(lchip, p_srh_tnl->l3edit_ptr);
            p_srh_tnl_p = _sys_usw_nh_lkup_srh_id(lchip, p_srh_tnl->p_srh_id);
            if (p_srh_tnl_w)
            {
                CTC_ERROR_RETURN(_sys_usw_nh_srv6_sid_num_check(lchip, p_nh_srv6_param, p_srh_tnl_w, p_nhdb));
            }
            if (p_srh_tnl_p)
            {
                CTC_ERROR_RETURN(_sys_usw_nh_srv6_sid_num_check(lchip, p_nh_srv6_param, p_srh_tnl_p, p_nhdb));
            }
        }
        else
        {
            CTC_ERROR_RETURN(_sys_usw_nh_srv6_sid_num_check(lchip, p_nh_srv6_param, p_srh_tnl, p_nhdb));
        }

        p_nh_param->p_tnl = p_srh_tnl;
    }
    else if(CTC_FLAG_ISSET(p_nh_srv6_param->flag, CTC_NH_SRV6_FLAG_SRH_ECMP))
    {
        /*check and get ecmp info*/
        CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo_by_nhid(lchip, p_nh_srv6_param->srh_id, (sys_nh_info_com_t**)&p_ecmp_nh));
        if ((NULL == p_ecmp_nh) || (SYS_NH_TYPE_ECMP != p_ecmp_nh->hdr.nh_entry_type) || (0 == p_ecmp_nh->mem_is_tunnel))
        {
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] srv6 not support!\n");
            return CTC_E_NOT_SUPPORT;
        }
        p_nhdb->ecmp_if_id = p_ecmp_nh->ecmp_group_id;
        p_nhdb->gport = p_nh_srv6_param->srh_id;
        if(p_ecmp_nh->tunnel_is_ldp)
        {
            CTC_SET_FLAG(p_nhdb->flag, SYS_NH_SRV6_FLAG_SRH_IS_LDP);
        }
        else
        {
            CTC_UNSET_FLAG(p_nhdb->flag, SYS_NH_SRV6_FLAG_SRH_IS_LDP);
        }
        if(p_ecmp_nh->srh_replace_ipda)
        {
            CTC_SET_FLAG(p_nhdb->flag, SYS_NH_SRV6_FLAG_SRH_REPLACE_IPDA);
        }
        else
        {
            CTC_UNSET_FLAG(p_nhdb->flag, SYS_NH_SRV6_FLAG_SRH_REPLACE_IPDA);
        } 
    }

    /* ii. get output interface */
    if((0 == p_nhdb->ecmp_if_id) && !CTC_FLAG_ISSET(p_nh_srv6_param->flag, CTC_NH_SRV6_FLAG_REROUTE) && !p_nh_srv6_param->loop_nhid && p_nh_srv6_param->srh_id
        && !CTC_FLAG_ISSET(p_nh_param->p_tnl->flag, SYS_NH_SRH_FLAG_APS))
    {
        CTC_ERROR_RETURN(sys_usw_nh_get_arp_oif(lchip, p_nh_param->p_tnl->arp_id, &p_nh_param->oif, (uint8*)(p_nh_param->mac), &p_nh_param->hdr.is_drop, &p_nh_param->hdr.l3if_id));
        if (!p_nh_param->hdr.is_drop)
        {
            SYS_GLOBAL_PORT_CHECK(p_nh_param->oif.gport);
        }
    }

    /* iii. get loop nexthop info */
    if(p_nh_srv6_param->loop_nhid)
    {
        sys_nh_info_dsnh_t    nhinfo = {0};
        CTC_ERROR_RETURN(_sys_usw_nh_get_nhinfo(lchip, p_nh_srv6_param->loop_nhid, &nhinfo));
    }

    /*1.Create unresolved nh*/
    if (CTC_FLAG_ISSET(p_nh_srv6_param->flag, CTC_NH_SRV6_FLAG_UNROV))
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "Create unresolved srv6 nexthop\n");
        CTC_SET_FLAG(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_IS_UNROV);
        return CTC_E_NONE;
    }

    /*2.Create normal srv6 nh*/
    /*2.1 op dsnh,l2edit,l3edit*/

    CTC_ERROR_GOTO(_sys_usw_nh_srv6_build_dsnh(lchip, p_nh_param, p_nhdb, &dsfwd_param), ret, error_proc);
    p_nhdb->srh_id = p_nh_srv6_param->srh_id;

    /*3.Create Dwfwd*/
    if (p_nh_param->hdr.have_dsfwd)
    {
        CTC_ERROR_GOTO(_sys_usw_nh_srv6_add_dsfwd(lchip,  p_nh_param, p_com_db, 0), ret, error_proc);
    }
    if (DRV_FROM_AT(lchip) && p_nh_param->hdr.have_dsfwd1)
    {
        CTC_ERROR_GOTO(_sys_usw_nh_srv6_add_dsfwd(lchip,  p_nh_param, p_com_db, 1), ret, error_proc);
    }
    CTC_ERROR_GOTO(_sys_usw_nh_srv6_update_tnl_mem(lchip, (sys_nh_info_com_t*)p_nhdb, p_srh_tnl, 1), ret, error_proc);
    return CTC_E_NONE;
    error_proc:
    _sys_usw_nh_free_srv6_resource(lchip, p_nhdb, NULL);
    return ret;
}


int32
sys_usw_nh_delete_srv6_cb(uint8 lchip, sys_nh_info_com_t* p_data, sys_nh_param_com_t* p_para)
{
    sys_nh_info_srv6_t* p_nh_info   = NULL;
    sys_nh_ref_list_node_t* p_ref_node, * p_tmp_node;

    p_nh_info = (sys_nh_info_srv6_t*)(p_data);

    if(p_para->hdr.p_nh_info_ext && p_para->hdr.p_nh_info_ext->ecmp_list)
    {
        sys_usw_nh_update_ecmp_member(lchip, p_data->hdr.nh_id, SYS_NH_CHANGE_TYPE_NH_DELETE, p_para->hdr.p_nh_info_ext->ecmp_list);
        /*1. delete all reference ecmp nh*/
        p_ref_node = p_para->hdr.p_nh_info_ext->ecmp_list;

        while (p_ref_node)
        {
            /*Remove from db*/
            p_tmp_node = p_ref_node;
            p_ref_node = p_ref_node->p_next;
            mem_free(p_tmp_node);
        }
        p_para->hdr.p_nh_info_ext->ecmp_list = NULL;
    }
    if(p_nh_info->bind_data)
    {
        mem_free(p_nh_info->bind_data);
    }

    /*2. Delete dsfwd*/
    _sys_usw_nh_remove_dsfwd(lchip, p_data);
    _sys_usw_nh_free_srv6_resource(lchip, p_nh_info, NULL);
    return CTC_E_NONE;
}

int32
sys_usw_nh_update_srv6_cb(uint8 lchip, sys_nh_info_com_t* p_nh_db,
                                     sys_nh_param_com_t* p_para)
{
    sys_nh_info_srv6_t* p_nh_info;
    sys_nh_param_srv6_t* p_nh_para;

    CTC_EQUAL_CHECK(SYS_NH_TYPE_SRV6, p_nh_db->hdr.nh_entry_type);
    p_nh_info = (sys_nh_info_srv6_t*)(p_nh_db);
    p_nh_para = (sys_nh_param_srv6_t*)(p_para);

    switch (p_nh_para->hdr.change_type)
    {
    case SYS_NH_CHANGE_TYPE_FWD_TO_UNROV:
        CTC_ERROR_RETURN(_sys_usw_nh_update_srv6_fwd_to_spec(lchip, p_nh_para, p_nh_info));
        break;

    case SYS_NH_CHANGE_TYPE_UPDATE_FWD_ATTR:
        CTC_ERROR_RETURN(_sys_usw_nh_update_srv6_fwd_attr(lchip, p_nh_para, p_nh_info));
        break;

    case SYS_NH_CHANGE_TYPE_UNROV_TO_FWD:

        if (!CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_IS_UNROV))
        {
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] Current nexthop isnt unresolved nexthop \n");
            return CTC_E_INVALID_CONFIG;

        }

        CTC_ERROR_RETURN(_sys_usw_nh_update_srv6_fwd_attr(lchip, p_nh_para, p_nh_info));
        break;
  case SYS_NH_CHANGE_TYPE_ADD_DYNTBL:
        {
          SYS_NH_DSFWD_CHK(p_nh_info->hdr.nh_entry_flags, p_para->hdr.is_dsfwd1);
          CTC_ERROR_RETURN(_sys_usw_nh_srv6_add_dsfwd(lchip,  NULL, p_nh_db, p_para->hdr.is_dsfwd1));
        }
        break;
    default:
        return CTC_E_INVALID_PARAM;
    }

    if (p_nh_para->hdr.p_nh_info_ext && p_nh_para->hdr.p_nh_info_ext->ecmp_list)
    {
        int32 ret = 0;
        ret = (sys_usw_nh_update_ecmp_member(lchip, p_nh_para->hdr.nhid, p_nh_para->hdr.change_type, p_nh_para->hdr.p_nh_info_ext->ecmp_list));
        if (ret)
        {
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] Nexthop update for ecmp fail!, ret:%d \n", ret);
        }
    }
    if (p_nh_para->hdr.p_nh_info_ext && (p_nh_para->hdr.change_type != SYS_NH_CHANGE_TYPE_ADD_DYNTBL))
   {
        sys_nh_ref_list_node_t* p_ref_node = NULL;
        sys_nh_info_com_t* p_nh_com = NULL;

        p_ref_node = p_nh_para->hdr.p_nh_info_ext->aps_list;
        while (p_ref_node)
        {
            p_nh_com = p_ref_node->p_ref_nhinfo;
            sys_usw_nh_update_aps_by_nh(lchip, p_nh_com->hdr.nh_id, p_nh_info->hdr.nh_id);
            p_ref_node = p_ref_node->p_next;
        }
   }

    if (CTC_FLAG_ISSET(p_nh_db->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_LOOP_USED))
    {
        CTC_ERROR_RETURN(sys_usw_nh_update_loopback_l2edit(lchip, p_nh_para->hdr.nhid, 1));
    }

    return CTC_E_NONE;
}

int32
sys_usw_nh_get_srv6_cb(uint8 lchip, sys_nh_info_com_t* p_nh_db, void* p_para)
{
    sys_nh_info_srv6_t* p_nh_info;
    ctc_nh_srv6_param_t* p_srv6_param = NULL;
    ctc_l3if_t l3if_info;
    uint32 cmd = 0;
    ipv6_addr_t hw_ipv6_address;
    DsL3TunnelV6IpSa_m v6_sa;
    uint32 stats_ptr = 0;
    sys_nh_db_srh_t    *p_srh_tnl = NULL;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    CTC_PTR_VALID_CHECK(p_para);
    p_nh_info = (sys_nh_info_srv6_t*)(p_nh_db);
    p_srv6_param = (ctc_nh_srv6_param_t*)p_para;
    sal_memset(&hw_ipv6_address, 0, sizeof(ipv6_addr_t));

    if (CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_IS_UNROV))
    {
        CTC_SET_FLAG(p_srv6_param->flag, CTC_NH_SRV6_FLAG_UNROV);
        return CTC_E_NONE;
    }
    if (CTC_FLAG_ISSET(p_nh_db->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_LB_WITH_LOGIC_DST))
    {
        CTC_SET_FLAG(p_srv6_param->flag, CTC_NH_SRV6_FLAG_LB_WITH_LOGIC_DST_PORT);
    }
    if (CTC_FLAG_ISSET(p_nh_info->flag, SYS_NH_SRV6_FLAG_REROUTE))
    {
        CTC_SET_FLAG(p_srv6_param->flag, CTC_NH_SRV6_FLAG_REROUTE);
    }

    if (CTC_FLAG_ISSET(p_nh_db->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_EGRESS_EDIT_MODE))
    {
        p_srv6_param->dsnh_offset = p_nh_db->hdr.dsnh_offset;
    }
    p_srv6_param->srv6_type = p_nh_info->srv6_type;
    p_srv6_param->srh_id = p_nh_info->srh_id;
    if (p_nh_info->ecmp_if_id)
    {
        CTC_SET_FLAG(p_srv6_param->flag, CTC_NH_SRV6_FLAG_SRH_ECMP);
        p_srv6_param->srh_id = p_nh_info->gport;
    }
    p_srv6_param->logic_port = p_nh_info->dest_logic_port;
    p_srv6_param->fp_id = p_nh_info->fp_id;
    p_srv6_param->service_id = p_nh_info->service_id;
    if (CTC_FLAG_ISSET(p_nh_info->flag, SYS_NH_SRV6_FLAG_LOOP_NH) )
    {
       sys_usw_nh_get_loopback_l2edit( lchip, p_nh_info->outer_l2_edit_offset ,&p_srv6_param->loop_nhid, 1);
    }

    sal_memset(&l3if_info, 0, sizeof(l3if_info));
    l3if_info.l3if_type = 0xff;

    if (CTC_FLAG_ISSET(p_nh_info->flag, SYS_NH_SRV6_FLAG_HAVE_IPSA))
    {
        cmd = DRV_IOR(DsL3TunnelV6IpSa_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, p_nh_info->ipsa_index, cmd, &v6_sa));
        GetDsL3TunnelV6IpSa(A, ipSa_f, &v6_sa, hw_ipv6_address);
    }

    p_srv6_param->ip_sa[0] = (hw_ipv6_address[3]);
    p_srv6_param->ip_sa[1] = (hw_ipv6_address[2]);
    p_srv6_param->ip_sa[2] = (hw_ipv6_address[1]);
    p_srv6_param->ip_sa[3] = (hw_ipv6_address[0]);

    p_srh_tnl = _sys_usw_nh_lkup_srh_id(lchip, p_nh_info->srh_id);
    if ((((p_srh_tnl && !p_srh_tnl->num) && !CTC_FLAG_ISSET(p_srh_tnl->flag, SYS_NH_SRH_FLAG_APS)) 
        || ((0 != p_nh_info->ecmp_if_id) && !CTC_FLAG_ISSET(p_nh_info->flag, SYS_NH_SRV6_FLAG_SRH_IS_LDP)))
        && (p_nh_info->dsl3edit_offset))
    {
        sys_dsl3edit_tunnelv6_t tunnel_v6;
        sys_dsl3edit_tunnelv6_t* dsl3edit_tunnelv6 = &tunnel_v6;

        sal_memset(&tunnel_v6, 0, sizeof(tunnel_v6));
        tunnel_v6.share_type = SYS_NH_L3EDIT_TUNNELV6_SHARE_TYPE_NORMAL;
        CTC_ERROR_RETURN(sys_usw_nh_read_asic_table(lchip, SYS_NH_ENTRY_TYPE_L3EDIT_TUNNEL_V6, p_nh_info->dsl3edit_offset, &tunnel_v6));

        p_srv6_param->ttl = dsl3edit_tunnelv6->ttl;
        if (dsl3edit_tunnelv6->map_ttl)
        {
            CTC_SET_FLAG(p_srv6_param->flag, CTC_NH_SRV6_FLAG_MAP_TTL);
        }
        p_srv6_param->dscp_domain = dsl3edit_tunnelv6->dscp_domain;

        p_srv6_param->mtu_size = dsl3edit_tunnelv6->mtu_size;
        if (dsl3edit_tunnelv6->mtu_check_en)
        {
            CTC_SET_FLAG(p_srv6_param->flag, CTC_NH_SRV6_FLAG_MTU_CHECK);
        }
        if (dsl3edit_tunnelv6->new_flow_label_valid)
        {
            p_srv6_param->flow_label = dsl3edit_tunnelv6->flow_label;
            p_srv6_param->flow_label_mode = dsl3edit_tunnelv6->new_flow_label_mode?CTC_NH_FLOW_LABEL_WITH_HASH:CTC_NH_FLOW_LABEL_ASSIGN;
        }

        if (0 == dsl3edit_tunnelv6->derive_dscp)
        {
            p_srv6_param->dscp_select = CTC_NH_DSCP_SELECT_NONE;
        }
        else if (1 == dsl3edit_tunnelv6->derive_dscp)
        {
            p_srv6_param->dscp_select = CTC_NH_DSCP_SELECT_ASSIGN;
            p_srv6_param->dscp_or_tos = dsl3edit_tunnelv6->tos >> 2;
        }
        else if (2 == dsl3edit_tunnelv6->derive_dscp)
        {
            p_srv6_param->dscp_select = CTC_NH_DSCP_SELECT_MAP;
        }
        else if (3 == dsl3edit_tunnelv6->derive_dscp)
        {
            p_srv6_param->dscp_select = CTC_NH_DSCP_SELECT_PACKET;
        }

        if (0 == dsl3edit_tunnelv6->ecn_mode)
        {
            p_srv6_param->ecn_select =  CTC_NH_ECN_SELECT_PACKET;
        }
        else if(1 == dsl3edit_tunnelv6->ecn_mode)
        {
            p_srv6_param->ecn_select = CTC_FLAG_ISSET(p_nh_info->flag, SYS_NH_SRV6_FLAG_ENCAP)? CTC_NH_ECN_SELECT_MAP : CTC_NH_ECN_SELECT_NONE;
        }
        else if (2 == dsl3edit_tunnelv6->ecn_mode)
        {
            p_srv6_param->ecn_select = CTC_NH_ECN_SELECT_MAP;
        }
        else if (3 == dsl3edit_tunnelv6->ecn_mode)
        {
            p_srv6_param->ecn_select = CTC_NH_ECN_SELECT_NONE;
        }
        p_srv6_param->ip_da[3] = dsl3edit_tunnelv6->ipda[0];
        p_srv6_param->ip_da[2] = dsl3edit_tunnelv6->ipda[1];
        p_srv6_param->ip_da[1] = dsl3edit_tunnelv6->ipda[2];
        p_srv6_param->ip_da[0] = dsl3edit_tunnelv6->ipda[3];

        stats_ptr = tunnel_v6.stats_ptr;
    }
    else if (CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L3EDIT))
    {
        sys_dsl3edit_srv6_t dsl3edit;
        sys_dsl3edit_srv6_t* dsl3edit_srv6 = &dsl3edit;
        uint8 table_type = SYS_NH_ENTRY_TYPE_L3EDIT_RW_SRV6;
        sal_memset(&dsl3edit, 0, sizeof(sys_dsl3edit_srv6_t));
        if (CTC_FLAG_ISSET(p_nh_info->flag, SYS_NH_SRV6_FLAG_ENCAP))
        {
            table_type = SYS_NH_ENTRY_TYPE_L3EDIT_ADD_SRV6;
        }
        CTC_ERROR_RETURN(sys_usw_nh_read_asic_table(lchip, table_type, p_nh_info->dsl3edit_offset, dsl3edit_srv6));
        p_srv6_param->ttl = dsl3edit_srv6->ttl;
        if (dsl3edit_srv6->map_ttl)
        {
            CTC_SET_FLAG(p_srv6_param->flag, CTC_NH_SRV6_FLAG_MAP_TTL);
        }
        if (dsl3edit_srv6->upd_chksum)
        {
            CTC_SET_FLAG(p_srv6_param->flag, CTC_NH_SRV6_FLAG_UPDATE_UDP_CHKSUM);
        }
        p_srv6_param->dscp_domain = dsl3edit_srv6->dscp_domain;

        p_srv6_param->mtu_size = dsl3edit_srv6->mtu_size;
        if (dsl3edit_srv6->mtu_check_en)
        {
            CTC_SET_FLAG(p_srv6_param->flag, CTC_NH_SRV6_FLAG_MTU_CHECK);
        }
        if (dsl3edit_srv6->new_flow_label_valid)
        {
            p_srv6_param->flow_label = dsl3edit_srv6->flow_label;
            p_srv6_param->flow_label_mode = dsl3edit_srv6->new_flow_label_mode?CTC_NH_FLOW_LABEL_WITH_HASH:CTC_NH_FLOW_LABEL_ASSIGN;
        }

        if (1 == dsl3edit_srv6->derive_dscp)
        {
            p_srv6_param->dscp_select = CTC_NH_DSCP_SELECT_ASSIGN;
            p_srv6_param->dscp_or_tos = dsl3edit_srv6->tos >> 2;
        }
        else if (2 == dsl3edit_srv6->derive_dscp)
        {
            p_srv6_param->dscp_select = CTC_NH_DSCP_SELECT_MAP;
        }
        else if (3 == dsl3edit_srv6->derive_dscp)
        {
            p_srv6_param->dscp_select = CTC_NH_DSCP_SELECT_PACKET;
        }

        if (0 == dsl3edit_srv6->ecn_mode)
        {
            p_srv6_param->ecn_select =  CTC_NH_ECN_SELECT_PACKET;
        }
        else if(1 == dsl3edit_srv6->ecn_mode)
        {
            p_srv6_param->ecn_select = CTC_FLAG_ISSET(p_nh_info->flag, SYS_NH_SRV6_FLAG_ENCAP)? CTC_NH_ECN_SELECT_MAP : CTC_NH_ECN_SELECT_NONE;
        }
        else if (2 == dsl3edit_srv6->ecn_mode)
        {
            p_srv6_param->ecn_select = CTC_NH_ECN_SELECT_MAP;
        }
        else if (3 == dsl3edit_srv6->ecn_mode)
        {
            p_srv6_param->ecn_select = CTC_NH_ECN_SELECT_NONE;
        }
        p_srv6_param->ip_da[3] = dsl3edit_srv6->ipda[0];
        p_srv6_param->ip_da[2] = dsl3edit_srv6->ipda[1];
        p_srv6_param->ip_da[1] = dsl3edit_srv6->ipda[2];
        p_srv6_param->ip_da[0] = dsl3edit_srv6->ipda[3];
        p_srv6_param->vpn_sid[3] = dsl3edit_srv6->vpn_sid[0];
        p_srv6_param->vpn_sid[2] = dsl3edit_srv6->vpn_sid[1];
        p_srv6_param->vpn_sid[1] = dsl3edit_srv6->vpn_sid[2];
        p_srv6_param->vpn_sid[0] = dsl3edit_srv6->vpn_sid[3];

        stats_ptr = dsl3edit_srv6->stats_ptr;
    }

    if ((p_srv6_param->flow_label_mode != CTC_NH_FLOW_LABEL_NONE)
        && CTC_FLAG_ISSET(p_nh_info->flag, SYS_NH_SRV6_FLAG_ENCAP))
    {
        sys_nexthop_t dsnh;

        sal_memset(&dsnh, 0, sizeof(dsnh));
        CTC_ERROR_RETURN(sys_usw_nh_read_asic_table(lchip,
                                                    CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W)? SYS_NH_ENTRY_TYPE_NEXTHOP_8W : SYS_NH_ENTRY_TYPE_NEXTHOP_4W,
                                                    p_nh_info->hdr.dsnh_offset, &dsnh));

        stats_ptr = dsnh.stats_ptr;
        if (dsnh.cid_valid)
        {
            p_srv6_param->cid = dsnh.cid;
        }
    }

    if (stats_ptr)
    {
        sys_usw_flow_stats_lookup_statsid(lchip, 0, stats_ptr, &p_srv6_param->stats_id, CTC_EGRESS);
    }

    if (CTC_FLAG_ISSET(p_nh_info->flag, SYS_NH_SRV6_FLAG_VLAN_EDIT) && p_srv6_param->vlan_info)
    {
        ctc_vlan_egress_edit_info_t* p_vlan_info = p_srv6_param->vlan_info;
        ds0_t ds_nh;
        uint32 cmd = 0;
        uint32 tbl_id = 0;
        tbl_id = (CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W)?DsNextHop8W_t:DsNextHop4W_t);
        cmd = DRV_IOR(tbl_id, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, p_nh_info->hdr.dsnh_offset, cmd, &ds_nh));
        p_vlan_info->svlan_edit_type = p_nh_info->svlan_edit_type;
        p_vlan_info->cvlan_edit_type = p_nh_info->cvlan_edit_type;
        //p_vlan_info->svlan_tpid_index = p_nh_info->tpid_index;
        _sys_usw_nh_decode_vlan_edit(lchip, p_vlan_info, &ds_nh);
        if (CTC_NH_SRV6_TYPE_H_ENCAPS_L2 == p_srv6_param->srv6_type)
        {
            CTC_UNSET_FLAG(p_vlan_info->flag, CTC_VLAN_NH_HORIZON_SPLIT_EN);
        }
    }


    return CTC_E_NONE;
}
